301 lines
7.7 KiB
Rust
301 lines
7.7 KiB
Rust
use logos::Logos;
|
|
use std::fmt;
|
|
|
|
/// CNNL词法Token定义
|
|
#[derive(Logos, Debug, Clone, PartialEq)]
|
|
#[logos(skip r"[ \t\n\f]+")] // 跳过空白字符
|
|
#[logos(skip r"//[^\n]*")] // 跳过单行注释
|
|
#[logos(skip r"/\*([^*]|\*[^/])*\*/")] // 跳过多行注释
|
|
pub enum Token {
|
|
// 关键字 - 条款结构
|
|
#[token("clause")]
|
|
Clause,
|
|
|
|
#[token("level")]
|
|
Level,
|
|
|
|
#[token("title")]
|
|
Title,
|
|
|
|
#[token("depends_on")]
|
|
DependsOn,
|
|
|
|
// 关键字 - 条款层级
|
|
#[token("eternal")]
|
|
Eternal,
|
|
|
|
#[token("strategic")]
|
|
Strategic,
|
|
|
|
#[token("tactical")]
|
|
Tactical,
|
|
|
|
// 关键字 - 参数和谓词
|
|
#[token("parameter")]
|
|
Parameter,
|
|
|
|
#[token("predicate")]
|
|
Predicate,
|
|
|
|
#[token("obligation")]
|
|
Obligation,
|
|
|
|
// 关键字 - 义务属性
|
|
#[token("frequency")]
|
|
Frequency,
|
|
|
|
#[token("enforcer")]
|
|
Enforcer,
|
|
|
|
#[token("penalty")]
|
|
Penalty,
|
|
|
|
// 关键字 - 频率值
|
|
#[token("continuous")]
|
|
Continuous,
|
|
|
|
#[token("periodic")]
|
|
Periodic,
|
|
|
|
#[token("on_demand")]
|
|
OnDemand,
|
|
|
|
// 关键字 - 控制流
|
|
#[token("if")]
|
|
If,
|
|
|
|
#[token("else")]
|
|
Else,
|
|
|
|
#[token("return")]
|
|
Return,
|
|
|
|
// 类型关键字
|
|
#[token("bool")]
|
|
Bool,
|
|
|
|
#[token("u64")]
|
|
U64,
|
|
|
|
#[token("u32")]
|
|
U32,
|
|
|
|
#[token("f64")]
|
|
F64,
|
|
|
|
#[token("string")]
|
|
String_,
|
|
|
|
// 字面量
|
|
#[regex(r"[0-9]+", |lex| lex.slice().parse::<u64>().ok())]
|
|
IntLiteral(u64),
|
|
|
|
#[regex(r"[0-9]+\.[0-9]+", |lex| lex.slice().parse::<f64>().ok())]
|
|
FloatLiteral(f64),
|
|
|
|
#[token("true", |_| true)]
|
|
#[token("false", |_| false)]
|
|
BoolLiteral(bool),
|
|
|
|
#[regex(r#""([^"\\]|\\.)*""#, |lex| {
|
|
let s = lex.slice();
|
|
Some(s[1..s.len()-1].to_string())
|
|
})]
|
|
StringLiteral(String),
|
|
|
|
// 标识符
|
|
#[regex(r"[A-Z][A-Z0-9_]+", |lex| lex.slice().to_string())]
|
|
ConstantIdent(String), // 全大写标识符(常量)
|
|
|
|
#[regex(r"[a-z_][a-z0-9_]*", |lex| lex.slice().to_string())]
|
|
Ident(String), // 小写标识符
|
|
|
|
// 运算符
|
|
#[token("+")]
|
|
Plus,
|
|
|
|
#[token("-")]
|
|
Minus,
|
|
|
|
#[token("*")]
|
|
Star,
|
|
|
|
#[token("/")]
|
|
Slash,
|
|
|
|
#[token("%")]
|
|
Percent,
|
|
|
|
#[token("==")]
|
|
Eq,
|
|
|
|
#[token("!=")]
|
|
Ne,
|
|
|
|
#[token("<")]
|
|
Lt,
|
|
|
|
#[token("<=")]
|
|
Le,
|
|
|
|
#[token(">")]
|
|
Gt,
|
|
|
|
#[token(">=")]
|
|
Ge,
|
|
|
|
#[token("&&")]
|
|
And,
|
|
|
|
#[token("||")]
|
|
Or,
|
|
|
|
#[token("!")]
|
|
Not,
|
|
|
|
// 分隔符
|
|
#[token("(")]
|
|
LParen,
|
|
|
|
#[token(")")]
|
|
RParen,
|
|
|
|
#[token("{")]
|
|
LBrace,
|
|
|
|
#[token("}")]
|
|
RBrace,
|
|
|
|
#[token("[")]
|
|
LBracket,
|
|
|
|
#[token("]")]
|
|
RBracket,
|
|
|
|
#[token(":")]
|
|
Colon,
|
|
|
|
#[token(",")]
|
|
Comma,
|
|
|
|
#[token("=")]
|
|
Assign,
|
|
|
|
#[token("->")]
|
|
Arrow,
|
|
}
|
|
|
|
impl fmt::Display for Token {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Token::Clause => write!(f, "clause"),
|
|
Token::Level => write!(f, "level"),
|
|
Token::Title => write!(f, "title"),
|
|
Token::DependsOn => write!(f, "depends_on"),
|
|
Token::Eternal => write!(f, "eternal"),
|
|
Token::Strategic => write!(f, "strategic"),
|
|
Token::Tactical => write!(f, "tactical"),
|
|
Token::Parameter => write!(f, "parameter"),
|
|
Token::Predicate => write!(f, "predicate"),
|
|
Token::Obligation => write!(f, "obligation"),
|
|
Token::Frequency => write!(f, "frequency"),
|
|
Token::Enforcer => write!(f, "enforcer"),
|
|
Token::Penalty => write!(f, "penalty"),
|
|
Token::Continuous => write!(f, "continuous"),
|
|
Token::Periodic => write!(f, "periodic"),
|
|
Token::OnDemand => write!(f, "on_demand"),
|
|
Token::If => write!(f, "if"),
|
|
Token::Else => write!(f, "else"),
|
|
Token::Return => write!(f, "return"),
|
|
Token::Bool => write!(f, "bool"),
|
|
Token::U64 => write!(f, "u64"),
|
|
Token::U32 => write!(f, "u32"),
|
|
Token::F64 => write!(f, "f64"),
|
|
Token::String_ => write!(f, "string"),
|
|
Token::IntLiteral(n) => write!(f, "{}", n),
|
|
Token::FloatLiteral(n) => write!(f, "{}", n),
|
|
Token::BoolLiteral(b) => write!(f, "{}", b),
|
|
Token::StringLiteral(s) => write!(f, "\"{}\"", s),
|
|
Token::ConstantIdent(s) => write!(f, "{}", s),
|
|
Token::Ident(s) => write!(f, "{}", s),
|
|
Token::Plus => write!(f, "+"),
|
|
Token::Minus => write!(f, "-"),
|
|
Token::Star => write!(f, "*"),
|
|
Token::Slash => write!(f, "/"),
|
|
Token::Percent => write!(f, "%"),
|
|
Token::Eq => write!(f, "=="),
|
|
Token::Ne => write!(f, "!="),
|
|
Token::Lt => write!(f, "<"),
|
|
Token::Le => write!(f, "<="),
|
|
Token::Gt => write!(f, ">"),
|
|
Token::Ge => write!(f, ">="),
|
|
Token::And => write!(f, "&&"),
|
|
Token::Or => write!(f, "||"),
|
|
Token::Not => write!(f, "!"),
|
|
Token::LParen => write!(f, "("),
|
|
Token::RParen => write!(f, ")"),
|
|
Token::LBrace => write!(f, "{{"),
|
|
Token::RBrace => write!(f, "}}"),
|
|
Token::LBracket => write!(f, "["),
|
|
Token::RBracket => write!(f, "]"),
|
|
Token::Colon => write!(f, ":"),
|
|
Token::Comma => write!(f, ","),
|
|
Token::Assign => write!(f, "="),
|
|
Token::Arrow => write!(f, "->"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_keywords() {
|
|
let mut lex = Token::lexer("clause level eternal parameter predicate");
|
|
assert_eq!(lex.next(), Some(Ok(Token::Clause)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Level)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Eternal)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Parameter)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Predicate)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_literals() {
|
|
let mut lex = Token::lexer("123 3.14 true false \"hello\"");
|
|
assert_eq!(lex.next(), Some(Ok(Token::IntLiteral(123))));
|
|
assert_eq!(lex.next(), Some(Ok(Token::FloatLiteral(3.14))));
|
|
assert_eq!(lex.next(), Some(Ok(Token::BoolLiteral(true))));
|
|
assert_eq!(lex.next(), Some(Ok(Token::BoolLiteral(false))));
|
|
assert_eq!(lex.next(), Some(Ok(Token::StringLiteral("hello".to_string()))));
|
|
}
|
|
|
|
#[test]
|
|
fn test_identifiers() {
|
|
let mut lex = Token::lexer("XTZH_GOLD_COVERAGE check_coverage");
|
|
assert_eq!(lex.next(), Some(Ok(Token::ConstantIdent("XTZH_GOLD_COVERAGE".to_string()))));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Ident("check_coverage".to_string()))));
|
|
}
|
|
|
|
#[test]
|
|
fn test_operators() {
|
|
let mut lex = Token::lexer("+ - * / >= <= == !=");
|
|
assert_eq!(lex.next(), Some(Ok(Token::Plus)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Minus)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Star)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Slash)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Ge)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Le)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Eq)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Ne)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_comments() {
|
|
let mut lex = Token::lexer("clause // comment\nlevel /* block comment */ eternal");
|
|
assert_eq!(lex.next(), Some(Ok(Token::Clause)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Level)));
|
|
assert_eq!(lex.next(), Some(Ok(Token::Eternal)));
|
|
}
|
|
}
|