use crate::{
diag::Syntax,
lexer::{NumType, Token},
Either, Span, Spanned,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Omittable<T> {
Some(T),
None,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Ident {
pub name: String,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Node {
pub ty: NodeTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum NodeTy {
Empty,
Expr(Expr),
Block(Scope),
VarDef { type_: Type, ident: Ident },
VarDefs(Vec<(Type, Ident)>),
VarDefInit {
type_: Type,
ident: Ident,
value: Option<Expr>,
},
VarDefInits(Vec<(Type, Ident)>, Option<Expr>),
InterfaceDef {
qualifiers: Vec<Qualifier>,
ident: Ident,
body: Scope,
instance: Omittable<Expr>,
},
Qualifiers(Vec<Qualifier>),
FnDecl {
return_type: Type,
ident: Ident,
params: Vec<Param>,
},
FnDef {
return_type: Type,
ident: Ident,
params: Vec<Param>,
body: Scope,
},
SubroutineTypeDecl {
return_type: Type,
ident: Ident,
params: Vec<Param>,
},
SubroutineFnDef {
associations: Vec<Ident>,
return_type: Type,
ident: Ident,
params: Vec<Param>,
body: Option<Scope>,
},
SubroutineUniformDef { type_: Type, ident: Ident },
StructDecl {
qualifiers: Vec<Qualifier>,
ident: Ident,
},
StructDef {
qualifiers: Vec<Qualifier>,
ident: Ident,
body: Scope,
instance: Omittable<Ident>,
},
If(Vec<IfBranch>),
Switch {
cond: Option<Expr>,
cases: Vec<SwitchCase>,
},
For {
init: Option<Box<Node>>,
cond: Option<Box<Node>>,
inc: Option<Box<Node>>,
body: Option<Scope>,
},
While { cond: Option<Expr>, body: Scope },
DoWhile { body: Scope, cond: Option<Expr> },
Break,
Continue,
Discard,
Return { value: Omittable<Expr> },
EmptyDirective,
VersionDirective {
version: Option<Spanned<usize>>,
profile: Omittable<Spanned<ProfileTy>>,
},
ExtensionDirective {
name: Option<Spanned<String>>,
behaviour: Option<Spanned<BehaviourTy>>,
},
LineDirective {
line: Option<Spanned<usize>>,
src_str_num: Omittable<Spanned<usize>>,
},
DefineDirective {
macro_: Macro,
replacement_tokens: Vec<Spanned<Token>>,
},
UndefDirective {
name: Omittable<Ident>,
},
ErrorDirective { message: Omittable<Spanned<String>> },
PragmaDirective { options: Omittable<Spanned<String>> },
}
#[derive(Debug, Clone, PartialEq)]
pub struct Scope {
pub contents: Vec<Node>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Param {
pub type_: Type,
pub ident: Omittable<Ident>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct IfBranch {
pub condition: Spanned<IfCondition>,
pub body: Option<Scope>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum IfCondition {
If(Option<Expr>),
ElseIf(Option<Expr>),
Else,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SwitchCase {
pub expr: Either<Option<Expr>, ()>,
pub body: Option<Scope>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Type {
pub ty: TypeTy,
pub qualifiers: Vec<Qualifier>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum TypeTy {
Single(Primitive),
Array(Primitive, ArrSize),
Array2D(Primitive, ArrSize, ArrSize),
ArrayND(Primitive, Vec<ArrSize>),
}
pub type ArrSize = Omittable<Expr>;
#[derive(Debug, Clone, PartialEq)]
pub enum Primitive {
Scalar(Fundamental),
Vector(Fundamental, usize),
Matrix(usize, usize),
DMatrix(usize, usize),
Struct(Ident),
Sampler(Fundamental, TexType),
Image(Fundamental, TexType),
Atomic,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Fundamental {
Void,
Bool,
Int,
UInt,
Float,
Double,
}
#[derive(Debug, Clone, PartialEq)]
pub enum TexType {
D1,
D2,
D3,
Cube,
D2Rect,
D1Array,
D2Array,
CubeArray,
Buffer,
D2Multisample,
D2MultisampleArray,
D1Shadow,
D2Shadow,
D3Shadow,
CubeShadow,
D2RectShadow,
D1ArrayShadow,
D2ArrayShadow,
CubeArrayShadow,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Qualifier {
pub ty: QualifierTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum QualifierTy {
Const,
In,
Out,
InOut,
Attribute,
Uniform,
Varying,
Buffer,
Shared,
Centroid,
Sample,
Patch,
Layout(Vec<Layout>),
Flat,
Smooth,
NoPerspective,
HighP,
MediumP,
LowP,
Invariant,
Precise,
Coherent,
Volatile,
Restrict,
Readonly,
Writeonly,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Layout {
pub ty: LayoutTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LayoutTy {
Shared,
Packed,
Std140,
Std430,
RowMajor,
ColumnMajor,
Binding(Option<Expr>),
Offset(Option<Expr>),
Align(Option<Expr>),
Location(Option<Expr>),
Component(Option<Expr>),
Index(Option<Expr>),
Points,
Lines,
Isolines,
Triangles,
Quads,
EqualSpacing,
FractionalEvenSpacing,
FractionalOddSpacing,
Clockwise,
CounterClockwise,
PointMode,
LineAdjacency,
TriangleAdjacency,
Invocations(Option<Expr>),
OriginUpperLeft,
PixelCenterInteger,
EarlyFragmentTests,
LocalSizeX(Option<Expr>),
LocalSizeY(Option<Expr>),
LocalSizeZ(Option<Expr>),
XfbBuffer(Option<Expr>),
XfbStride(Option<Expr>),
XfbOffset(Option<Expr>),
Vertices(Option<Expr>),
LineStrip,
TriangleStrip,
MaxVertices(Option<Expr>),
Stream(Option<Expr>),
DepthAny,
DepthGreater,
DepthLess,
DepthUnchanged,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ProfileTy {
Core,
Compatability,
Es,
}
#[derive(Debug, Clone, PartialEq)]
pub enum BehaviourTy {
Require,
Enable,
Warn,
Disable,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Macro {
Object { ident: Ident },
Function { ident: Ident, params: Vec<Ident> },
}
impl<T> Omittable<T> {
#[inline]
pub const fn is_some(&self) -> bool {
matches!(*self, Self::Some(_))
}
#[inline]
pub const fn is_none(&self) -> bool {
!self.is_some()
}
}
impl<T> From<Option<T>> for Omittable<T> {
fn from(opt: Option<T>) -> Self {
match opt {
Some(val) => Omittable::Some(val),
None => Omittable::None,
}
}
}
impl Type {
pub fn parse(expr: &Expr) -> Option<Self> {
match &expr.ty {
ExprTy::Ident(i) => Some(Self {
span: expr.span,
ty: TypeTy::Single(Primitive::parse(i)),
qualifiers: vec![],
}),
ExprTy::Index { item, i } => {
let mut current_item = item;
let mut stack = Vec::new();
stack.push(i.as_deref().cloned().into());
let primitive = loop {
match ¤t_item.ty {
ExprTy::Ident(i) => break Primitive::parse(i),
ExprTy::Index { item, i } => {
stack.push(i.as_deref().cloned().into());
current_item = item;
}
_ => {
return None;
}
}
};
stack.reverse();
Some(Self {
span: expr.span,
ty: if stack.len() == 1 {
TypeTy::Array(primitive, stack.remove(0))
} else if stack.len() == 2 {
let one = stack.remove(0);
let two = stack.remove(0);
TypeTy::Array2D(primitive, one, two)
} else {
TypeTy::ArrayND(primitive, stack)
},
qualifiers: vec![],
})
}
_ => None,
}
}
pub(crate) fn parse_var_idents(
expr: &Expr,
) -> Option<Vec<(Ident, Vec<ArrSize>)>> {
fn convert(expr: &Expr) -> Option<(Ident, Vec<ArrSize>)> {
match &expr.ty {
ExprTy::Ident(i) => Some((i.clone(), vec![])),
ExprTy::Index { item, i } => {
let mut current_item = item;
let mut stack = Vec::new();
stack.push(i.as_deref().cloned().into());
let ident = loop {
match ¤t_item.ty {
ExprTy::Ident(i) => break i.clone(),
ExprTy::Index { item, i } => {
stack.push(i.as_deref().cloned().into());
current_item = item;
}
_ => {
return None;
}
}
};
stack.reverse();
Some((ident, stack))
}
_ => unreachable!(),
}
}
match &expr.ty {
ExprTy::Ident(_) | ExprTy::Index { .. } => {
convert(expr).map(|i| vec![i])
}
ExprTy::List { items } => {
let mut v = Vec::new();
for item in items {
v.push(match convert(item) {
Some(i) => i,
None => return None,
})
}
Some(v)
}
_ => None,
}
}
}
impl Primitive {
pub fn parse(ident: &Ident) -> Self {
match ident.name.as_ref() {
"void" => Primitive::Scalar(Fundamental::Void),
"bool" => Primitive::Scalar(Fundamental::Bool),
"int" => Primitive::Scalar(Fundamental::Int),
"uint" => Primitive::Scalar(Fundamental::UInt),
"float" => Primitive::Scalar(Fundamental::Float),
"double" => Primitive::Scalar(Fundamental::Double),
"vec2" => Primitive::Vector(Fundamental::Float, 2),
"vec3" => Primitive::Vector(Fundamental::Float, 3),
"vec4" => Primitive::Vector(Fundamental::Float, 4),
"bvec2" => Primitive::Vector(Fundamental::Bool, 2),
"bvec3" => Primitive::Vector(Fundamental::Bool, 3),
"bvec4" => Primitive::Vector(Fundamental::Bool, 4),
"ivec2" => Primitive::Vector(Fundamental::Int, 2),
"ivec3" => Primitive::Vector(Fundamental::Int, 3),
"ivec4" => Primitive::Vector(Fundamental::Int, 4),
"uvec2" => Primitive::Vector(Fundamental::UInt, 2),
"uvec3" => Primitive::Vector(Fundamental::UInt, 3),
"uvec4" => Primitive::Vector(Fundamental::UInt, 4),
"dvec2" => Primitive::Vector(Fundamental::Double, 2),
"dvec3" => Primitive::Vector(Fundamental::Double, 3),
"dvec4" => Primitive::Vector(Fundamental::Double, 4),
"mat2" => Primitive::Matrix(2, 2),
"mat2x2" => Primitive::Matrix(2, 2),
"mat2x3" => Primitive::Matrix(2, 3),
"mat2x4" => Primitive::Matrix(2, 4),
"mat3x2" => Primitive::Matrix(3, 2),
"mat3" => Primitive::Matrix(3, 3),
"mat3x3" => Primitive::Matrix(3, 3),
"mat3x4" => Primitive::Matrix(3, 4),
"mat4x2" => Primitive::Matrix(4, 2),
"mat4x3" => Primitive::Matrix(4, 3),
"mat4" => Primitive::Matrix(4, 4),
"mat4x4" => Primitive::Matrix(4, 4),
"dmat2" => Primitive::DMatrix(2, 2),
"dmat2x2" => Primitive::DMatrix(2, 2),
"dmat2x3" => Primitive::DMatrix(2, 3),
"dmat2x4" => Primitive::DMatrix(2, 4),
"dmat3x2" => Primitive::DMatrix(3, 2),
"dmat3" => Primitive::DMatrix(3, 3),
"dmat3x3" => Primitive::DMatrix(3, 3),
"dmat3x4" => Primitive::DMatrix(3, 4),
"dmat4x2" => Primitive::DMatrix(4, 2),
"dmat4x3" => Primitive::DMatrix(4, 3),
"dmat4" => Primitive::DMatrix(4, 4),
"dmat4x4" => Primitive::DMatrix(4, 4),
"sampler1D" => Primitive::Sampler(Fundamental::Float, TexType::D1),
"sampler2D" => Primitive::Sampler(Fundamental::Float, TexType::D2),
"sampler3D" => Primitive::Sampler(Fundamental::Float, TexType::D3),
"samplerCube" => {
Primitive::Sampler(Fundamental::Float, TexType::Cube)
}
"sampler2DRect" => {
Primitive::Sampler(Fundamental::Float, TexType::D2Rect)
}
"sampler1DArray" => {
Primitive::Sampler(Fundamental::Float, TexType::D1Array)
}
"sampler2DArray" => {
Primitive::Sampler(Fundamental::Float, TexType::D2Array)
}
"samplerCubeArray" => {
Primitive::Sampler(Fundamental::Float, TexType::CubeArray)
}
"samplerBuffer" => {
Primitive::Sampler(Fundamental::Float, TexType::Buffer)
}
"sampler2DMS" => {
Primitive::Sampler(Fundamental::Float, TexType::D2Multisample)
}
"sampler2DMSArray" => Primitive::Sampler(
Fundamental::Float,
TexType::D2MultisampleArray,
),
"isampler1D" => Primitive::Sampler(Fundamental::Int, TexType::D1),
"isampler2D" => Primitive::Sampler(Fundamental::Int, TexType::D2),
"isampler3D" => Primitive::Sampler(Fundamental::Int, TexType::D3),
"isamplerCube" => {
Primitive::Sampler(Fundamental::Int, TexType::Cube)
}
"isampler2DRect" => {
Primitive::Sampler(Fundamental::Int, TexType::D2Rect)
}
"isampler1DArray" => {
Primitive::Sampler(Fundamental::Int, TexType::D1Array)
}
"isampler2DArray" => {
Primitive::Sampler(Fundamental::Int, TexType::D2Array)
}
"isamplerCubeArray" => {
Primitive::Sampler(Fundamental::Int, TexType::CubeArray)
}
"isamplerBuffer" => {
Primitive::Sampler(Fundamental::Int, TexType::Buffer)
}
"isampler2DMS" => {
Primitive::Sampler(Fundamental::Int, TexType::D2Multisample)
}
"isampler2DMSArray" => Primitive::Sampler(
Fundamental::Int,
TexType::D2MultisampleArray,
),
"usampler1D" => Primitive::Sampler(Fundamental::UInt, TexType::D1),
"usampler2D" => Primitive::Sampler(Fundamental::UInt, TexType::D2),
"usampler3D" => Primitive::Sampler(Fundamental::UInt, TexType::D3),
"usamplerCube" => {
Primitive::Sampler(Fundamental::UInt, TexType::Cube)
}
"usampler2DRect" => {
Primitive::Sampler(Fundamental::UInt, TexType::D2Rect)
}
"usampler1DArray" => {
Primitive::Sampler(Fundamental::UInt, TexType::D1Array)
}
"usampler2DArray" => {
Primitive::Sampler(Fundamental::UInt, TexType::D2Array)
}
"usamplerCubeArray" => {
Primitive::Sampler(Fundamental::UInt, TexType::CubeArray)
}
"usamplerBuffer" => {
Primitive::Sampler(Fundamental::UInt, TexType::Buffer)
}
"usampler2DMS" => {
Primitive::Sampler(Fundamental::UInt, TexType::D2Multisample)
}
"usampler2DMSArray" => Primitive::Sampler(
Fundamental::UInt,
TexType::D2MultisampleArray,
),
"sampler1DShadow" => {
Primitive::Sampler(Fundamental::Float, TexType::D1Shadow)
}
"sampler2DShadow" => {
Primitive::Sampler(Fundamental::Float, TexType::D2Shadow)
}
"samplerCubeShadow" => {
Primitive::Sampler(Fundamental::Float, TexType::CubeShadow)
}
"sampler2DRectShadow" => {
Primitive::Sampler(Fundamental::Float, TexType::D2RectShadow)
}
"sampler1DArrayShadow" => {
Primitive::Sampler(Fundamental::Float, TexType::D1ArrayShadow)
}
"sampler2DArrayShadow" => {
Primitive::Sampler(Fundamental::Float, TexType::D2ArrayShadow)
}
"samplerCubeArrayShadow" => {
Primitive::Sampler(Fundamental::Float, TexType::CubeArrayShadow)
}
"image1D" => Primitive::Image(Fundamental::Float, TexType::D1),
"image2D" => Primitive::Image(Fundamental::Float, TexType::D2),
"image3D" => Primitive::Image(Fundamental::Float, TexType::D3),
"imageCube" => Primitive::Image(Fundamental::Float, TexType::Cube),
"image2DRect" => {
Primitive::Image(Fundamental::Float, TexType::D2Rect)
}
"image1DArray" => {
Primitive::Image(Fundamental::Float, TexType::D1Array)
}
"image2DArray" => {
Primitive::Image(Fundamental::Float, TexType::D2Array)
}
"imageCubeArray" => {
Primitive::Image(Fundamental::Float, TexType::CubeArray)
}
"imageBuffer" => {
Primitive::Image(Fundamental::Float, TexType::Buffer)
}
"image2DMS" => {
Primitive::Image(Fundamental::Float, TexType::D2Multisample)
}
"image2DMSArray" => Primitive::Image(
Fundamental::Float,
TexType::D2MultisampleArray,
),
"iimage1D" => Primitive::Image(Fundamental::Int, TexType::D1),
"iimage2D" => Primitive::Image(Fundamental::Int, TexType::D2),
"iimage3D" => Primitive::Image(Fundamental::Int, TexType::D3),
"iimageCube" => Primitive::Image(Fundamental::Int, TexType::Cube),
"iimage2DRect" => {
Primitive::Image(Fundamental::Int, TexType::D2Rect)
}
"iimage1DArray" => {
Primitive::Image(Fundamental::Int, TexType::D1Array)
}
"iimage2DArray" => {
Primitive::Image(Fundamental::Int, TexType::D2Array)
}
"iimageCubeArray" => {
Primitive::Image(Fundamental::Int, TexType::CubeArray)
}
"iimageBuffer" => {
Primitive::Image(Fundamental::Int, TexType::Buffer)
}
"iimage2DMS" => {
Primitive::Image(Fundamental::Int, TexType::D2Multisample)
}
"iimage2DMSArray" => {
Primitive::Image(Fundamental::Int, TexType::D2MultisampleArray)
}
"uimage1D" => Primitive::Image(Fundamental::UInt, TexType::D1),
"uimage2D" => Primitive::Image(Fundamental::UInt, TexType::D2),
"uimage3D" => Primitive::Image(Fundamental::UInt, TexType::D3),
"uimageCube" => Primitive::Image(Fundamental::UInt, TexType::Cube),
"uimage2DRect" => {
Primitive::Image(Fundamental::UInt, TexType::D2Rect)
}
"uimage1DArray" => {
Primitive::Image(Fundamental::UInt, TexType::D1Array)
}
"uimage2DArray" => {
Primitive::Image(Fundamental::UInt, TexType::D2Array)
}
"uimageCubeArray" => {
Primitive::Image(Fundamental::UInt, TexType::CubeArray)
}
"uimageBuffer" => {
Primitive::Image(Fundamental::UInt, TexType::Buffer)
}
"uimage2DMS" => {
Primitive::Image(Fundamental::UInt, TexType::D2Multisample)
}
"uimage2DMSArray" => {
Primitive::Image(Fundamental::UInt, TexType::D2MultisampleArray)
}
"atomic_uint" => Primitive::Atomic,
_ => Primitive::Struct(ident.clone()),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Expr {
pub ty: ExprTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExprTy {
Lit(Lit),
Ident(Ident),
Prefix { op: PreOp, expr: Option<Box<Expr>> },
Postfix { expr: Box<Expr>, op: PostOp },
Binary {
left: Box<Expr>,
op: BinOp,
right: Option<Box<Expr>>,
},
Ternary {
cond: Box<Expr>,
true_: Option<Box<Expr>>,
false_: Option<Box<Expr>>,
},
Parens { expr: Option<Box<Expr>> },
ObjAccess {
obj: Box<Expr>,
leaf: Option<Box<Expr>>,
},
Index {
item: Box<Expr>,
i: Option<Box<Expr>>,
},
FnCall { ident: Ident, args: Vec<Expr> },
InitList { args: Vec<Expr> },
ArrConstructor {
arr: Box<Expr>,
args: Vec<Expr>,
},
List { items: Vec<Expr> },
Separator,
}
#[derive(Debug, Clone, PartialEq)]
pub struct BinOp {
pub ty: BinOpTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum BinOpTy {
Add,
Sub,
Mul,
Div,
Rem,
And,
Or,
Xor,
LShift,
RShift,
Eq,
AddEq,
SubEq,
MulEq,
DivEq,
RemEq,
AndEq,
OrEq,
XorEq,
LShiftEq,
RShiftEq,
EqEq,
NotEq,
AndAnd,
OrOr,
XorXor,
Gt,
Lt,
Ge,
Le,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PreOp {
pub ty: PreOpTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PreOpTy {
Add,
Sub,
Neg,
Flip,
Not,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PostOp {
pub ty: PostOpTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PostOpTy {
Add,
Sub,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Lit {
Bool(bool),
Int(i64),
UInt(u64),
Float(f32),
Double(f64),
InvalidNum,
}
impl Lit {
pub fn parse(token: &Token, span: Span) -> Result<Self, (Self, Syntax)> {
use crate::diag::ExprDiag;
match token {
Token::Bool(b) => Ok(Self::Bool(*b)),
Token::Num {
num: s,
suffix,
type_,
} => {
let s: &str = &s;
let suffix = suffix.as_deref();
let type_ = *type_;
if s == "" {
return Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::EmptyNumber(span)),
));
}
match type_ {
NumType::Dec => Self::parse_num_dec(s, suffix, span),
NumType::Hex => Self::parse_num_hex(s, suffix, span),
NumType::Oct => Self::parse_num_oct(s, suffix, span),
NumType::Float => Self::parse_num_float(s, suffix, span),
}
}
_ => unreachable!(
"This function should only be given a `Num` or `Bool` token."
),
}
}
fn parse_num_dec(
s: &str,
suffix: Option<&str>,
span: Span,
) -> Result<Self, (Self, Syntax)> {
use crate::diag::ExprDiag;
if let Some(suffix) = suffix {
if suffix == "u" || suffix == "U" {
if let Ok(u) = u64::from_str_radix(s, 10) {
return Ok(Self::UInt(u));
}
} else {
return Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::InvalidNumber(span)),
));
}
} else {
if let Ok(i) = i64::from_str_radix(s, 10) {
return Ok(Self::Int(i));
}
}
Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::UnparsableNumber(span)),
))
}
fn parse_num_hex(
s: &str,
suffix: Option<&str>,
span: Span,
) -> Result<Self, (Self, Syntax)> {
use crate::diag::ExprDiag;
if let Some(suffix) = suffix {
if suffix == "u" || suffix == "U" {
if let Ok(u) = u64::from_str_radix(s, 16) {
return Ok(Self::UInt(u));
}
} else {
return Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::InvalidNumber(span)),
));
}
} else {
if let Ok(i) = i64::from_str_radix(s, 16) {
return Ok(Self::Int(i));
}
}
Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::UnparsableNumber(span)),
))
}
fn parse_num_oct(
s: &str,
suffix: Option<&str>,
span: Span,
) -> Result<Self, (Self, Syntax)> {
use crate::diag::ExprDiag;
if let Some(suffix) = suffix {
if suffix == "u" || suffix == "U" {
if let Ok(u) = u64::from_str_radix(s, 8) {
return Ok(Self::UInt(u));
}
} else {
return Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::InvalidNumber(span)),
));
}
} else {
if let Ok(i) = i64::from_str_radix(s, 8) {
return Ok(Self::Int(i));
}
}
Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::UnparsableNumber(span)),
))
}
fn parse_num_float(
s: &str,
suffix: Option<&str>,
span: Span,
) -> Result<Self, (Self, Syntax)> {
use crate::diag::ExprDiag;
if let Some(suffix) = suffix {
if suffix == "lf" || suffix == "LF" {
if let Ok(f) = s.parse::<f64>() {
return Ok(Self::Double(f));
}
} else if suffix == "f" || suffix == "F" {
if let Ok(f) = s.parse::<f32>() {
return Ok(Self::Float(f));
}
} else {
return Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::InvalidNumber(span)),
));
}
} else {
if let Ok(f) = s.parse::<f32>() {
return Ok(Self::Float(f));
}
}
Err((
Self::InvalidNum,
Syntax::Expr(ExprDiag::UnparsableNumber(span)),
))
}
}
pub(crate) mod conditional {
use super::Ident;
use crate::Span;
#[derive(Debug, Clone, PartialEq)]
pub struct Expr {
pub ty: ExprTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExprTy {
Num(usize),
Prefix { op: PreOp, expr: Option<Box<Expr>> },
Binary {
left: Box<Expr>,
op: BinOp,
right: Option<Box<Expr>>,
},
Parens { expr: Option<Box<Expr>> },
Defined { ident: Ident },
}
#[derive(Debug, Clone, PartialEq)]
pub struct BinOp {
pub ty: BinOpTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum BinOpTy {
Add,
Sub,
Mul,
Div,
Rem,
And,
Or,
Xor,
LShift,
RShift,
EqEq,
NotEq,
AndAnd,
OrOr,
Gt,
Lt,
Ge,
Le,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PreOp {
pub ty: PreOpTy,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PreOpTy {
Neg,
Flip,
Not,
}
}