pub use std::os::raw::c_char;
pub const MAX_IDENTIFIER_LENGTH: usize = 64;
pub const MAX_NUMBER_LENGTH: usize = 256;
#[derive(Clone, Copy)]
pub struct Identifier {
pub value: [c_char; MAX_IDENTIFIER_LENGTH],
pub length: usize,
}
impl Identifier {
pub fn new () -> Self {
Self {
value: [ 0 as c_char; MAX_IDENTIFIER_LENGTH ],
length: 0
}
}
pub fn from_str (new_value: &str) -> Option<Self> {
let mut value = [ 0 as c_char; MAX_IDENTIFIER_LENGTH ];
let length = new_value.len();
for (i, ch) in new_value.chars().enumerate() {
if ch.is_ascii() {
value[i] = ch as c_char;
} else {
return None;
}
}
Some(Self {
value,
length
})
}
}
impl std::cmp::PartialEq for Identifier {
fn eq (&self, r: &Identifier) -> bool {
if self.length == r.length {
for i in 0..self.length {
if self.value[i] != r.value[i] {
return false
}
}
true
} else {
false
}
}
}
impl std::fmt::Debug for Identifier {
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
for i in 0..self.length {
write!(f, "{}", self.value[i] as u8 as char)?;
}
Ok(())
}
}
impl std::fmt::Display for Identifier {
fn fmt (&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
#[repr(u8)]
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)]
pub enum ConstantNumber {
NaN,
Infinity,
}
#[repr(u8)]
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)]
pub enum NumberFormat {
Binary,
DecimalInteger,
DecimalFloatingPoint,
Hexadecimal,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Number {
Integer(u64),
Character(char),
FloatingPoint(f64),
Constant(ConstantNumber)
}
impl Number {
pub fn is_integer (&self) -> bool {
match self {
Number::Integer(_) => true,
_ => false
}
}
pub fn is_character (&self) -> bool {
match self {
Number::Character(_) => true,
_ => false
}
}
pub fn is_floating_point (&self) -> bool {
match self {
Number::FloatingPoint(_) => true,
_ => false
}
}
pub fn is_constant (&self) -> bool {
match self {
Number::Constant(_) => true,
_ => false
}
}
pub fn get_integer (&self) -> Option<&u64> {
match self {
Number::Integer(i) => Some(i),
_ => None
}
}
pub fn get_character (&self) -> Option<&char> {
match self {
Number::Character(c) => Some(c),
_ => None
}
}
pub fn get_floating_point (&self) -> Option<&f64> {
match self {
Number::FloatingPoint(f) => Some(f),
_ => None
}
}
pub fn get_constant (&self) -> Option<&ConstantNumber> {
match self {
Number::Constant(c) => Some(c),
_ => None
}
}
}
#[derive(Debug, Clone)]
pub enum Literal {
Nil,
Boolean(bool),
Number(Number),
String(String),
}
impl Literal {
pub fn is_nil (&self) -> bool {
match self {
Literal::Nil => true,
_ => false
}
}
pub fn is_boolean (&self) -> bool {
match self {
Literal::Boolean(_) => true,
_ => false
}
}
pub fn is_number (&self) -> bool {
match self {
Literal::Number(_) => true,
_ => false
}
}
pub fn is_string (&self) -> bool {
match self {
Literal::String(_) => true,
_ => false
}
}
pub fn get_boolean (&self) -> Option<&bool> {
match self {
Literal::Boolean(b) => Some(b),
_ => None
}
}
pub fn get_number (&self) -> Option<&Number> {
match self {
Literal::Number(n) => Some(n),
_ => None
}
}
pub fn get_string (&self) -> Option<&String> {
match self {
Literal::String(s) => Some(s),
_ => None
}
}
}
#[derive(Debug, Clone)]
pub enum Primary {
Literal(Literal),
Identifier(Identifier),
}
impl Primary {
pub fn is_literal (&self) -> bool {
match self {
Primary::Literal(_) => true,
_ => false
}
}
pub fn is_ident (&self) -> bool {
match self {
Primary::Identifier(_) => true,
_ => false
}
}
pub fn get_literal (&self) -> Option<&Literal> {
match self {
Primary::Literal(lit) => Some(lit),
_ => None
}
}
pub fn get_ident (&self) -> Option<&Identifier> {
match self {
Primary::Identifier(ident) => Some(ident),
_ => None
}
}
}
#[derive(Debug, Clone)]
pub enum MaybeIgnore<T: std::fmt::Debug + Clone> {
Ignore,
Value(T)
}
impl<T: std::fmt::Debug + Clone> MaybeIgnore<T> {
pub fn is_ignore (&self) -> bool {
match self {
MaybeIgnore::Ignore => true,
_ => false
}
}
pub fn is_value (&self) -> bool {
match self {
MaybeIgnore::Value(_) => true,
_ => false
}
}
pub fn to_option (self) -> Option<T> {
match self {
MaybeIgnore::Value(v) => Some(v),
_ => None
}
}
}
#[repr(u8)]
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)]
pub enum OperatorType {
Add, Sub, Mul, Div, Rem,
AddAssign, SubAssign, MulAssign, DivAssign, RemAssign,
Assign,
AddressOf,
Dereference,
Mutable,
Arrow,
WideArrow,
Dot,
Semi,
Colon,
Comma,
ExclusiveRange,
InclusiveRange,
LesserOrEqual, GreaterOrEqual, Equal, NotEqual,
LogicalNot, LogicalAnd, LogicalOr, LogicalXor,
BitwiseNot, BitwiseAnd, BitwiseOr, BitwiseXor,
BitwiseLeftShift, BitwiseRightShift,
LeftParen, RightParen,
LeftBrace, RightBrace,
LeftBracket, RightBracket,
LeftAngle, RightAngle,
SizeOf, AlignOf, OffsetOf,
Cast,
OpenMetaTag,
}
#[repr(u8)]
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)]
pub enum KeywordType {
Mod,
Import, Export, Use,
Type, Struct, Union, Enum, Sum,
Impl,
Function,
Let,
If, Else,
Match,
For, While, Loop, Until,
In,
Break, Continue,
Return,
}
macro_rules! op {
( $( $($op: expr), * => $ov_op: ident ), * $(,)? ) => {
&[ $( (&[ $( $op ), * ], OperatorType::$ov_op) ), * ]
};
}
pub const OPERATOR_TYPE_SYMS: &[(&[char], OperatorType)] = op! [
'+' => Add,
'-' => Sub,
'*' => Mul,
'/' => Div,
'%' => Rem,
'+','=' => AddAssign,
'-','=' => SubAssign,
'*','=' => MulAssign,
'/','=' => DivAssign,
'%','=' => RemAssign,
'=' => Assign,
'^' => AddressOf,
'@' => Dereference,
'-','>' => Arrow,
'=','>' => WideArrow,
'.' => Dot,
';' => Semi,
':' => Colon,
',' => Comma,
'.','.' => ExclusiveRange,
'.','.','.' => InclusiveRange,
'<','=' => LesserOrEqual,
'>','=' => GreaterOrEqual,
'=','=' => Equal,
'!','=' => NotEqual,
'!' => BitwiseNot,
'&' => BitwiseAnd,
'|' => BitwiseOr,
'~' => BitwiseXor,
'(' => LeftParen,
')' => RightParen,
'[' => LeftBrace,
']' => RightBrace,
'{' => LeftBracket,
'}' => RightBracket,
'<' => LeftAngle,
'>' => RightAngle,
':', '<' => OpenMetaTag,
];
macro_rules! Overloads {
( $( $op: ident $( => $value: ident $(, $extras: ident ),* )? );* $(;)? ) => {
#[repr(u8)]
#[derive(Debug, PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)]
pub enum OverloadableOperatorType { $(
$op $( = OperatorType::$value as _ )?
),* }
pub const OVERLOADABLE_OPERATOR_TYPE_SYMS: &[(&[OperatorType], OverloadableOperatorType)] = &[ $(
(&[$( OperatorType::$value $( , OperatorType::$extras )* )?], OverloadableOperatorType::$op)
),* ];
};
}
Overloads! {
Add; Sub; Mul; Div; Rem;
Assign;
AddressOf; Dereference;
Arrow; Dot;
ExclusiveRange; InclusiveRange;
LesserOrEqual; GreaterOrEqual; Equal; NotEqual;
LogicalNot; LogicalAnd; LogicalOr; LogicalXor;
BitwiseNot; BitwiseAnd; BitwiseOr; BitwiseXor;
BitwiseLeftShift; BitwiseRightShift;
Subscript => LeftBrace, RightBrace;
Call => LeftParen, RightParen;
Cast;
}
pub const MOD_ASSIGN_OPS: &[OperatorType] = &[
OperatorType::AddAssign,
OperatorType::SubAssign,
OperatorType::MulAssign,
OperatorType::DivAssign,
OperatorType::RemAssign,
];
pub const TERMINATOR_OPS: &[OperatorType] = &[
OperatorType::Semi,
OperatorType::Comma,
OperatorType::RightParen,
OperatorType::RightBrace,
OperatorType::RightBracket,
OperatorType::RightAngle,
];
#[repr(u8)]
#[derive(PartialEq, Clone, Copy, FromPrimitive, ToPrimitive)]
pub enum InternalIdentifierType {
Nil,
Ignore,
Boolean,
ConstantNumber,
Operator,
Keyword,
}
macro_rules! id {
( $( $ty: ident [ $( $($id: expr),* => $val: expr ),* $(,)? ] ),* $(,)? ) => {
&[ $( $(
(&[$( $id as c_char ),*], InternalIdentifierType::$ty, $val as u8)
),* ),* ]
};
}
pub const INTERNAL_IDENTIFIERS: &[(&[c_char], InternalIdentifierType, u8)] = id! [
Nil [ 'n','i','l' => 0 ],
Ignore [ '_' => 0 ],
Boolean [
't','r','u','e' => true,
'f','a','l','s','e' => false,
],
ConstantNumber [
'n','a','n' => ConstantNumber::NaN,
'i','n','f' => ConstantNumber::Infinity,
],
Operator [
'm','u','t' => OperatorType::Mutable,
'n','o','t' => OperatorType::LogicalNot,
'a','n','d' => OperatorType::LogicalAnd,
'o','r' => OperatorType::LogicalOr,
'x','o','r' => OperatorType::LogicalXor,
'l','s','h','i','f','t' => OperatorType::BitwiseLeftShift,
'r','s','h','i','f','t' => OperatorType::BitwiseRightShift,
's','i','z','e','o','f' => OperatorType::SizeOf,
'a','l','i','g','n','o','f' => OperatorType::AlignOf,
'o','f','f','s','e','t','o','f' => OperatorType::OffsetOf,
'a','s' => OperatorType::Cast,
],
Keyword [
'm','o','d' => KeywordType::Mod,
'i','m','p','o','r','t' => KeywordType::Import,
'e','x','p','o','r','t' => KeywordType::Export,
'u','s','e' => KeywordType::Use,
't','y','p','e' => KeywordType::Type,
's','t','r','u','c','t' => KeywordType::Struct,
'u','n','i','o','n' => KeywordType::Union,
'e','n','u','m' => KeywordType::Enum,
's','u','m' => KeywordType::Sum,
'i','m','p','l' => KeywordType::Impl,
'f','n' => KeywordType::Function,
'l','e','t' => KeywordType::Let,
'i','f' => KeywordType::If,
'e','l','s','e' => KeywordType::Else,
'm','a','t','c','h' => KeywordType::Match,
'f','o','r' => KeywordType::For,
'w','h','i','l','e' => KeywordType::While,
'l','o','o','p' => KeywordType::Loop,
'u','n','t','i','l' => KeywordType::Until,
'i','n' => KeywordType::In,
'b','r','e','a','k' => KeywordType::Break,
'c','o','n','t','i','n','u','e' => KeywordType::Continue,
'r','e','t','u','r','n' => KeywordType::Return,
],
];
pub const LOOP_CONTROL_KWS: &[KeywordType] = &[
KeywordType::Break,
KeywordType::Continue,
];
pub const UNARY_POWER: usize = 70;
pub const UNARY_OPERATORS: &[OperatorType] = &[
OperatorType::Dereference,
OperatorType::LogicalNot,
OperatorType::BitwiseNot,
OperatorType::Add,
OperatorType::Sub,
OperatorType::SizeOf,
OperatorType::AlignOf,
OperatorType::OffsetOf,
];
macro_rules! bin_ops {
( $( ( $op: expr, $prec: expr ) ), * $(,)? ) => {
pub const BINARY_OPERATORS: &[OperatorType] = &[
$( $op ), *
];
pub const BINARY_PRECEDENCES: &[usize] = &[
$( $prec ), *
];
};
}
bin_ops! [
(OperatorType::LogicalAnd, 20),
(OperatorType::LogicalOr, 20),
(OperatorType::LogicalXor, 20),
(OperatorType::LeftAngle, 30),
(OperatorType::RightAngle, 30),
(OperatorType::LesserOrEqual, 30),
(OperatorType::GreaterOrEqual, 30),
(OperatorType::NotEqual, 30),
(OperatorType::Equal, 30),
(OperatorType::InclusiveRange, 40),
(OperatorType::ExclusiveRange, 40),
(OperatorType::Add, 50),
(OperatorType::Sub, 50),
(OperatorType::BitwiseAnd, 50),
(OperatorType::BitwiseOr, 50),
(OperatorType::BitwiseXor, 50),
(OperatorType::Mul, 60),
(OperatorType::Div, 60),
(OperatorType::Rem, 60),
(OperatorType::BitwiseLeftShift, 60),
(OperatorType::BitwiseRightShift, 60),
];
pub fn get_bin_op_precedence (op: OperatorType) -> usize {
for (i, bop) in BINARY_OPERATORS.iter().enumerate() {
if op == *bop {
return BINARY_PRECEDENCES[i];
}
}
panic!("Tried to get precedence for unregistered binary operator {:?}", op);
}
impl OperatorType {
pub fn as_text (self) -> String {
for sym in OPERATOR_TYPE_SYMS {
if sym.1 == self {
return sym.0.iter().collect();
}
}
for ident in INTERNAL_IDENTIFIERS {
if ident.1 == InternalIdentifierType::Operator
&& ident.2 == self as _ {
let mut out = String::new();
for c in ident.0 {
out.push(*c as u8 as _);
}
return out;
}
}
panic!("Could not find text value for OperatorType {:?}", self);
}
}
impl KeywordType {
pub fn as_text (self) -> String {
for ident in INTERNAL_IDENTIFIERS {
if ident.1 == InternalIdentifierType::Keyword
&& ident.2 == self as _ {
let mut out = String::new();
for c in ident.0 {
out.push(*c as u8 as _);
}
return out;
}
}
panic!("Could not find text value for KeywordType {:?}", self);
}
}