use std::{collections::HashMap, fmt::Display, ops::{Deref, DerefMut}, rc::Rc};
use crate::{RantProgramInfo, InternalString, RantValue, RantValueType};
pub(crate) const PIPE_VALUE_NAME: &str = "~PIPE";
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PrintFlag {
None,
Hint,
Sink
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Identifier(InternalString);
impl Identifier {
pub fn new(idstr: InternalString) -> Self {
Self(idstr)
}
}
impl From<&'static str> for Identifier {
fn from(s: &'static str) -> Self {
Self::new(InternalString::from(s))
}
}
impl std::borrow::Borrow<str> for Identifier {
fn borrow(&self) -> &str {
self.0.as_str()
}
}
impl Deref for Identifier {
type Target = InternalString;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
pub(crate) fn is_valid_ident(name: &str) -> bool {
if name.is_empty() { return false }
let mut has_non_digit = false;
let is_valid_chars = name.chars().all(|c| {
has_non_digit |= !c.is_ascii_digit();
c.is_alphanumeric() || matches!(c, '_' | '-')
});
has_non_digit && is_valid_chars
}
#[derive(Debug, Clone)]
pub enum SliceIndex {
Static(i64),
Dynamic(Rc<Sequence>)
}
impl Display for SliceIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SliceIndex::Static(i) => write!(f, "{}", i),
SliceIndex::Dynamic(_expr) => write!(f, "{{...}}"),
}
}
}
#[derive(Debug, Clone)]
pub enum SliceExpr {
Full,
From(SliceIndex),
To(SliceIndex),
Between(SliceIndex, SliceIndex),
}
impl SliceExpr {
pub(crate) fn as_static_slice<F: FnMut(&Rc<Sequence>) -> RantValue>(&self, mut index_converter: F) -> Result<Slice, RantValueType> {
macro_rules! convert_index {
($index:expr) => {
match $index {
SliceIndex::Static(i) => *i,
SliceIndex::Dynamic(expr) => {
match index_converter(expr) {
RantValue::Int(i) => i,
other => return Err(other.get_type())
}
}
}
}
}
Ok(match self {
SliceExpr::Full => Slice::Full,
SliceExpr::From(from) => Slice::From(convert_index!(from)),
SliceExpr::To(to) => Slice::To(convert_index!(to)),
SliceExpr::Between(from, to) => Slice::Between(convert_index!(from), convert_index!(to)),
})
}
}
impl Display for SliceExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SliceExpr::Full => write!(f, ":"),
SliceExpr::From(i) => write!(f, "{}:", i),
SliceExpr::To(i) => write!(f, ":{}", i),
SliceExpr::Between(l, r) => write!(f, "{}:{}", l, r),
}
}
}
#[derive(Debug)]
pub enum Slice {
Full,
From(i64),
To(i64),
Between(i64, i64),
}
#[derive(Debug, Clone)]
pub enum AccessPathComponent {
Name(Identifier),
Index(i64),
Slice(SliceExpr),
Expression(Rc<Sequence>),
PipeValue,
}
impl Display for AccessPathComponent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Name(name) => write!(f, "{name}"),
Self::Index(i) => write!(f, "{i}"),
Self::Slice(slice_expr) => write!(f, "{slice_expr}"),
Self::Expression(expr) => write!(f, "({}...)", expr.name().map(|name| name.as_str()).unwrap_or("")),
Self::PipeValue => write!(f, "[]"),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum VarAccessMode {
Local,
ExplicitGlobal,
Descope(usize),
}
impl VarAccessMode {
pub fn descope_count(&self) -> usize {
match self {
VarAccessMode::Local | VarAccessMode::ExplicitGlobal => 0,
VarAccessMode::Descope(n) => *n
}
}
#[inline]
pub fn is_local(&self) -> bool {
matches!(self, Self::Local)
}
}
#[derive(Debug, Clone)]
pub struct AccessPath {
path: Vec<AccessPathComponent>,
mode: VarAccessMode,
}
impl AccessPath {
#[inline]
pub fn new(path: Vec<AccessPathComponent>, kind: VarAccessMode) -> Self {
Self {
path,
mode: kind
}
}
#[inline]
pub fn add_descope(self, n: usize) -> Self {
Self {
mode: match self.mode {
VarAccessMode::Local => VarAccessMode::Descope(n),
VarAccessMode::Descope(d) => VarAccessMode::Descope(d + n),
VarAccessMode::ExplicitGlobal => VarAccessMode::ExplicitGlobal,
},
.. self
}
}
#[inline]
pub fn is_explicit_global(&self) -> bool {
matches!(self.mode, VarAccessMode::ExplicitGlobal)
}
#[inline]
pub fn is_anonymous(&self) -> bool {
matches!(self.first(), Some(AccessPathComponent::Expression(..) | AccessPathComponent::PipeValue))
}
#[inline]
pub fn is_variable_target(&self) -> bool {
self.len() == 1 && matches!(self.first(), Some(AccessPathComponent::Name(..) | AccessPathComponent::Expression(..) | AccessPathComponent::PipeValue))
}
#[inline]
pub fn is_anonymous_target(&self) -> bool {
self.len() == 1 && matches!(self.first(), Some(AccessPathComponent::Expression(..) | AccessPathComponent::PipeValue))
}
#[inline]
pub fn mode(&self) -> VarAccessMode {
self.mode
}
#[inline]
pub fn dynamic_exprs(&self) -> Vec<Rc<Sequence>> {
use AccessPathComponent::*;
let mut exprs = vec![];
for component in self.iter() {
match component {
Expression(expr) => exprs.push(Rc::clone(expr)),
Slice(SliceExpr::From(SliceIndex::Dynamic(expr)))
| Slice(SliceExpr::To(SliceIndex::Dynamic(expr)))
| Slice(SliceExpr::Between(SliceIndex::Static(_), SliceIndex::Dynamic(expr)))
| Slice(SliceExpr::Between(SliceIndex::Dynamic(expr), SliceIndex::Static(_))) => exprs.push(Rc::clone(expr)),
Slice(SliceExpr::Between(SliceIndex::Dynamic(expr_from), SliceIndex::Dynamic(expr_to))) => {
exprs.push(Rc::clone(expr_from));
exprs.push(Rc::clone(expr_to));
},
_ => {}
}
}
exprs
}
#[inline]
pub fn var_name(&self) -> Option<Identifier> {
if let Some(first) = self.first() {
return Some(match first {
AccessPathComponent::Name(id) => id.clone(),
AccessPathComponent::PipeValue => Identifier::from(PIPE_VALUE_NAME),
_ => return None
})
}
None
}
}
impl Deref for AccessPath {
type Target = Vec<AccessPathComponent>;
fn deref(&self) -> &Self::Target {
&self.path
}
}
impl DerefMut for AccessPath {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.path
}
}
impl Display for AccessPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.iter().map(|part| part.to_string()).collect::<Vec<String>>().join("/"))
}
}
#[derive(Debug)]
pub struct Sequence {
elements: Vec<Rc<Expression>>,
pub name: Option<InternalString>,
pub origin: Rc<RantProgramInfo>,
}
impl Sequence {
#[inline]
pub fn new(seq: Vec<Rc<Expression>>, origin: &Rc<RantProgramInfo>) -> Self {
Self {
elements: seq,
name: None,
origin: Rc::clone(origin),
}
}
#[inline]
pub fn one(rst: Expression, origin: &Rc<RantProgramInfo>) -> Self {
Self {
elements: vec![Rc::new(rst)],
name: None,
origin: Rc::clone(origin),
}
}
pub fn empty(origin: &Rc<RantProgramInfo>) -> Self {
Self::new(vec![], origin)
}
#[inline(always)]
pub fn with_name(mut self, name: InternalString) -> Self {
self.name = Some(name);
self
}
#[inline(always)]
pub fn with_name_str(mut self, name: &str) -> Self {
self.name = Some(InternalString::from(name));
self
}
pub fn name(&self) -> Option<&InternalString> {
self.name.as_ref()
}
}
impl Deref for Sequence {
type Target = Vec<Rc<Expression>>;
fn deref(&self) -> &Self::Target {
&self.elements
}
}
impl DerefMut for Sequence {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.elements
}
}
#[derive(Debug)]
pub struct Block {
pub is_weighted: bool,
pub protection: Option<BlockProtection>,
pub elements: Rc<Vec<Rc<BlockElement>>>
}
impl Block {
pub fn new(is_weighted: bool, protection: Option<BlockProtection>, elements: Vec<Rc<BlockElement>>) -> Self {
Block {
is_weighted,
protection,
elements: Rc::new(elements),
}
}
#[inline]
pub fn len(&self) -> usize {
self.elements.len()
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum BlockProtection {
Outer,
}
#[derive(Debug)]
pub struct BlockElement {
pub main: Rc<Sequence>,
pub weight: Option<BlockWeight>,
pub output_modifier: Option<OutputModifierSig>,
}
impl Clone for BlockElement {
#[inline]
fn clone(&self) -> Self {
Self {
main: Rc::clone(&self.main),
weight: self.weight.clone(),
output_modifier: self.output_modifier.clone(),
}
}
}
#[derive(Debug)]
pub enum BlockWeight {
Dynamic(Rc<Sequence>),
Constant(f64),
}
impl Clone for BlockWeight {
#[inline]
fn clone(&self) -> Self {
match self {
BlockWeight::Dynamic(s) => Self::Dynamic(Rc::clone(s)),
BlockWeight::Constant(c) => Self::Constant(*c),
}
}
}
#[derive(Debug, Clone)]
pub struct OutputModifierSig {
pub input_var: Option<Identifier>
}
#[derive(Debug, Copy, Clone)]
pub enum Varity {
Required,
Optional,
VariadicStar,
VariadicPlus,
}
impl Varity {
pub fn is_valid_order(first: Varity, second: Varity) -> bool {
use Varity::*;
matches!((first, second),
(Required, Required) |
(Required, Optional) |
(Required, VariadicStar) |
(Required, VariadicPlus) |
(Optional, Optional) |
(Optional, VariadicStar)
)
}
pub fn is_variadic(&self) -> bool {
use Varity::*;
matches!(self, VariadicStar | VariadicPlus)
}
}
impl Display for Varity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Varity::*;
match self {
Required => write!(f, "required parameter"),
Optional => write!(f, "optional parameter"),
VariadicStar => write!(f, "optional variadic parameter"),
VariadicPlus => write!(f, "required variadic parameter"),
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum ArgumentSpreadMode {
NoSpread,
Parametric,
Temporal { label: usize, is_complex: bool },
}
#[derive(Debug)]
pub struct ArgumentExpr {
pub expr: Rc<Sequence>,
pub spread_mode: ArgumentSpreadMode,
}
#[derive(Debug)]
pub enum FunctionCallTarget {
Path(Rc<AccessPath>),
}
#[derive(Debug)]
pub struct FunctionCall {
pub target: FunctionCallTarget,
pub arguments: Rc<Vec<ArgumentExpr>>,
pub is_temporal: bool,
}
#[derive(Debug)]
pub struct PipedCall {
pub steps: Rc<Vec<FunctionCall>>,
pub assignment_pipe: Option<Rc<AssignmentPipeTarget>>,
pub is_temporal: bool,
}
#[derive(Debug)]
pub enum AssignmentPipeTarget {
Set(Rc<AccessPath>),
Def { ident: Identifier, is_const: bool, access_mode: VarAccessMode },
}
#[derive(Debug)]
pub struct TemporalSpreadState {
counters: Vec<(usize, usize)>,
arg_labels: HashMap<usize, usize>,
}
impl TemporalSpreadState {
#[inline]
pub fn new(arg_exprs: &[ArgumentExpr], args: &[RantValue]) -> Self {
let mut counters = Vec::with_capacity(args.len());
let mut arg_labels: HashMap<usize, usize> = Default::default();
for (i, expr) in arg_exprs.iter().enumerate() {
if let ArgumentSpreadMode::Temporal { label, .. } = expr.spread_mode {
arg_labels.insert(i, label);
let arg = &args[i];
if label >= counters.len() {
let counter_size = if arg.is_indexable() {
arg.len()
} else {
0
};
counters.push((0, counter_size));
} else {
if arg.is_indexable() {
let (_, n) = &mut counters[label];
*n = arg.len().min(*n);
}
}
}
}
Self {
counters,
arg_labels,
}
}
#[inline]
pub fn len(&self) -> usize {
self.counters.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.counters.is_empty() || self.counters.iter().all(|(.., n)| *n == 0)
}
#[inline]
pub fn get(&self, arg_index: usize) -> Option<usize> {
self.arg_labels.get(&arg_index).map(|i| self.counters[*i].0)
}
#[inline]
pub fn increment(&mut self) -> bool {
let mut success = false;
for (c, n) in self.counters.iter_mut() {
*c += 1;
if c >= n {
*c = 0;
} else {
success = true;
break
}
}
success
}
}
#[derive(Debug, Clone)]
pub struct FunctionDef {
pub path: Rc<AccessPath>,
pub is_const: bool, pub params: Rc<Vec<Parameter>>,
pub capture_vars: Rc<Vec<Identifier>>,
pub body: Rc<Sequence>,
}
#[derive(Debug, Clone)]
pub struct LambdaExpr {
pub body: Rc<Sequence>,
pub params: Rc<Vec<Parameter>>,
pub capture_vars: Rc<Vec<Identifier>>,
}
#[derive(Debug)]
pub struct Parameter {
pub name: Identifier,
pub varity: Varity,
pub default_value_expr: Option<Rc<Sequence>>,
}
impl Parameter {
#[inline]
pub fn is_required(&self) -> bool {
use Varity::*;
matches!(self.varity, Required | VariadicPlus)
}
#[inline]
pub fn is_optional(&self) -> bool {
use Varity::*;
matches!(self.varity, Optional)
}
}
#[derive(Debug)]
pub enum MapKeyExpr {
Dynamic(Rc<Sequence>),
Static(InternalString),
}
#[derive(Debug)]
pub struct Getter {
pub path: Rc<AccessPath>,
pub fallback: Option<Rc<Sequence>>,
}
#[derive(Debug)]
pub struct Setter {
pub path: Rc<AccessPath>,
pub value: Rc<Sequence>,
}
#[derive(Debug, Copy, Clone)]
pub enum CompAssignOp {
Add,
Subtract,
Multiply,
Divide,
Modulo,
Power,
And,
Or,
Xor,
Nand,
Nor,
}
#[derive(Debug)]
pub struct Definition {
pub name: Identifier,
pub is_const: bool,
pub access_mode: VarAccessMode,
pub value: Option<Rc<Sequence>>,
}
#[derive(Debug)]
pub enum Expression {
Nop,
Sequence(Rc<Sequence>),
Block(Rc<Block>),
ListInit(Rc<Vec<Rc<Sequence>>>),
TupleInit(Rc<Vec<Rc<Sequence>>>),
MapInit(Rc<Vec<(MapKeyExpr, Rc<Sequence>)>>),
Lambda(LambdaExpr),
FuncCall(FunctionCall),
PipedCall(PipedCall),
FuncDef(FunctionDef),
Define(Definition),
Get(Getter),
Set(Setter),
PipeValue,
Fragment(InternalString),
Whitespace(InternalString),
Integer(i64),
Float(f64),
Boolean(bool),
NothingVal,
Return(Option<Rc<Sequence>>),
Continue(Option<Rc<Sequence>>),
Break(Option<Rc<Sequence>>),
LogicNot(Rc<Sequence>),
Negate(Rc<Sequence>),
Power(Rc<Sequence>, Rc<Sequence>),
Multiply(Rc<Sequence>, Rc<Sequence>),
Divide(Rc<Sequence>, Rc<Sequence>),
Modulo(Rc<Sequence>, Rc<Sequence>),
Add(Rc<Sequence>, Rc<Sequence>),
Subtract(Rc<Sequence>, Rc<Sequence>),
Less(Rc<Sequence>, Rc<Sequence>),
LessOrEqual(Rc<Sequence>, Rc<Sequence>),
Greater(Rc<Sequence>, Rc<Sequence>),
GreaterOrEqual(Rc<Sequence>, Rc<Sequence>),
Equals(Rc<Sequence>, Rc<Sequence>),
NotEquals(Rc<Sequence>, Rc<Sequence>),
LogicAnd(Rc<Sequence>, Rc<Sequence>),
LogicXor(Rc<Sequence>, Rc<Sequence>),
LogicOr(Rc<Sequence>, Rc<Sequence>),
Conditional { conditions: Rc<Vec<(Rc<Sequence>, Rc<Block>)>>, fallback: Option<Rc<Block>> },
DebugCursor(DebugInfo),
Require { alias: Option<InternalString>, path: InternalString },
}
impl Expression {
pub fn display_name(&self) -> &'static str {
match self {
Self::Sequence(_) => "sequence",
Self::Block(..) => "block",
Self::ListInit(_) => "list",
Self::TupleInit(_) => "tuple",
Self::MapInit(_) => "map",
Self::Lambda(_) => "lambda",
Self::FuncCall(_) => "call function",
Self::FuncDef(_) => "define function",
Self::Fragment(_) => "fragment",
Self::Whitespace(_) => "whitespace",
Self::Integer(_) => "integer",
Self::Float(_) => "float",
Self::Boolean(_) => "bool",
Self::NothingVal => "nothing_val",
Self::Nop => "no-op",
Self::Define(..) => "definition",
Self::Get(..) => "getter",
Self::Set(..) => "setter",
Self::PipedCall(_) => "piped call",
Self::PipeValue => "pipeval",
Self::Return(_) => "return",
Self::Continue(_) => "continue",
Self::Break(_) => "break",
Self::LogicNot(_) => "not",
Self::Negate(_) => "negate",
Self::Power(_, _) => "power",
Self::Multiply(_, _) => "multiply",
Self::Divide(_, _) => "divide",
Self::Modulo(_, _) => "modulo",
Self::Add(_, _) => "add",
Self::Subtract(_, _) => "subtract",
Self::Less(_, _) => "less than",
Self::LessOrEqual(_, _) => "less than or equal",
Self::Greater(_, _) => "greater than",
Self::GreaterOrEqual(_, _) => "greater than or equal",
Self::Equals(_, _) => "equals",
Self::NotEquals(_, _) => "not equals",
Self::LogicAnd(_, _) => "and",
Self::LogicXor(_, _) => "xor",
Self::LogicOr(_, _) => "or",
Self::DebugCursor(_) => "debug cursor",
Self::Conditional { .. } => "conditional",
Self::Require { .. } => "require",
}
}
}
impl Display for Expression {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.display_name())
}
}
#[derive(Debug)]
pub enum DebugInfo {
Location { line: usize, col: usize },
}