From 8032921182141f58ab3e0efa8699803ffa0adc30 Mon Sep 17 00:00:00 2001 From: Aoran Zeng Date: Wed, 16 Jul 2025 15:47:21 +0800 Subject: [PATCH] Strict types --- tool/rawstr4c/lib/Parser.rakumod | 68 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/tool/rawstr4c/lib/Parser.rakumod b/tool/rawstr4c/lib/Parser.rakumod index 5157734..9a335b6 100644 --- a/tool/rawstr4c/lib/Parser.rakumod +++ b/tool/rawstr4c/lib/Parser.rakumod @@ -13,10 +13,10 @@ unit module Parser; #| 不能用 Bool,只能用 Boolean -my enum ConfigItem's-ValueType ; +my enum ConfigItem's-ValueType < RS4C-Nil RS4C-String RS4C-Mode RS4C-Bool>; #| 配置项的值 -my class ConfigItem's-Value { +class ConfigItem's-Value { has ConfigItem's-ValueType $.type; has Str $.raw-value; has Any $.parsed-value; @@ -28,17 +28,24 @@ my class ConfigItem's-Value { given $raw-text { when /^ ':' (.+) $/ { # 模式值 :mode - $type = Mode; + $type = RS4C-Mode; $parsed = ~$0; } when /^ ('true'|'false'|'yes'|'no') $/ { # 特殊字面量 - true/false/yes/no 都是 literal - $type = Boolean; + $type = RS4C-Bool; $parsed = ~$0 ~~ /^('true'|'yes')$/ ?? True !! False; } + # 明确区分空字符串和无值情况 + # 这种情况不可能是用户写的(并没有nil这个字面量),只由内部实现时刻意传 Nil 出现 + when Nil { + $type = RS4C-Nil; + $parsed = Nil; + } + # 输入为空时被当做是字符串类型 default { # 普通字符串 - $type = String; + $type = RS4C-String; $parsed = $raw-text; } } @@ -46,30 +53,41 @@ my class ConfigItem's-Value { self.bless(:$type, :raw-value($raw-text), :parsed-value($parsed)); } - method as-string() { - return $.parsed-value.Str; - } - - method as-bool() { + # 获得适合调用者接受的值 + method value() { given $.type { - when Boolean { return $.parsed-value; } - when String { - # 尝试将字符串解析为布尔值 - return $.parsed-value ~~ /^('true'|'yes')$/; - } - default { return False; } + when RS4C-Nil | RS4C-String | RS4C-Bool | RS4C-Mode { return $.parsed-value; } + default { die "Unknown config value type: {$.type}"; } } } - # 获取模式值(去掉冒号前缀) - method as-mode() { - return $.type == Mode ?? $.parsed-value !! $.raw-value; + # 这些函数防止开发者写错类型 + method nil-value() { + return self.value if $.type == RS4C-Nil; + die "The config value type is not RS4C-Nil, but: {$.type}"; } + method string-value() { + return self.value if $.type == RS4C-String; + die "The config value type is not RS4C-String, but: {$.type}"; + } + + method bool-value() { + return self.value if $.type == RS4C-Bool; + die "The config value type is not RS4C-Bool, but: {$.type}"; + } + + method mode-value() { + return self.value if $.type == RS4C-Mode; + die "The config value type is not RS4C-Mode, but: {$.type}"; + } + + # 类型检查方法 - method is-mode() { return $.type == Mode; } - method is-bool() { return $.type == Boolean; } - method is-string() { return $.type == String; } + method is-nil() { return $.type == RS4C-Nil; } + method is-mode() { return $.type == RS4C-Mode; } + method is-bool() { return $.type == RS4C-Bool; } + method is-string() { return $.type == RS4C-String; } } @@ -85,8 +103,8 @@ my class ConfigBlock { %!items{$k} = ConfigItem's-Value.new($raw-value); } - method get($k, $default = Nil) { - return %!items{$k} // ($default ?? ConfigItem's-Value.new($default) !! ConfigItem's-Value.new('')); + method get($k) { + return %!items{$k}; } method exist($k) { @@ -102,7 +120,7 @@ my class ConfigBlock { #| 表示一个 section -my class Section { +class Section { has Str $.title; has Int $.level;