Added support for compile-time constant hash expressions

This commit is contained in:
2025-12-05 21:34:51 -07:00
parent 93b5f28ccb
commit 9993bff574
10 changed files with 150 additions and 21 deletions

View File

@@ -1256,17 +1256,47 @@ impl<'a> Parser<'a> {
));
}
// literal value
// literal or syscall, making sure the syscall is supported in hash
self.assign_next()?;
let lit = self.spanned(|p| p.literal())?;
// cache the current token location
let current_token_index = self.tokenizer.loc();
Ok(ConstDeclarationExpression {
name: Spanned {
span: ident_span,
node: ident,
},
value: lit,
})
if let Ok(lit) = self.spanned(|p| p.literal()) {
Ok(ConstDeclarationExpression {
name: Spanned {
span: ident_span,
node: ident,
},
value: LiteralOr::Literal(lit),
})
} else {
// we need to rewind our tokenizer to our previous location
self.tokenizer.seek(SeekFrom::Current(
self.tokenizer.loc() - current_token_index,
))?;
let syscall = self.spanned(|p| p.syscall())?;
if !matches!(
syscall,
Spanned {
node: SysCall::System(sys_call::System::Hash(_)),
..
}
) {
return Err(Error::UnexpectedToken(
syscall.span,
self.current_token.clone().ok_or(Error::UnexpectedEOF)?,
));
}
Ok(ConstDeclarationExpression {
name: Spanned {
span: ident_span,
node: ident,
},
value: LiteralOr::Or(syscall),
})
}
}
fn declaration(&mut self) -> Result<Expression, Error> {

View File

@@ -144,3 +144,10 @@ fn test_binary_expression() -> Result<()> {
Ok(())
}
#[test]
fn test_const_hash_expression() -> Result<()> {
let expr = parser!(r#"const i = hash("item")"#).parse()?.unwrap();
assert_eq!("(const i = hash(\"item\"))", expr.to_string());
Ok(())
}

View File

@@ -1,5 +1,7 @@
use std::ops::Deref;
use crate::sys_call;
use super::sys_call::SysCall;
use tokenizer::token::Number;
@@ -10,6 +12,21 @@ pub enum Literal {
Boolean(bool),
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum LiteralOr<T> {
Literal(Spanned<Literal>),
Or(Spanned<T>),
}
impl<T: std::fmt::Display> std::fmt::Display for LiteralOr<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Literal(l) => write!(f, "{l}"),
Self::Or(o) => write!(f, "{o}"),
}
}
}
impl std::fmt::Display for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@@ -198,7 +215,14 @@ impl std::fmt::Display for LiteralOrVariable {
#[derive(Debug, PartialEq, Eq)]
pub struct ConstDeclarationExpression {
pub name: Spanned<String>,
pub value: Spanned<Literal>,
pub value: LiteralOr<SysCall>,
}
impl ConstDeclarationExpression {
pub fn is_syscall_supported(call: &SysCall) -> bool {
use sys_call::System;
matches!(call, SysCall::System(sys) if matches!(sys, System::Hash(_)))
}
}
impl std::fmt::Display for ConstDeclarationExpression {