字面量以及标识符

 

数字字面量

FunC 支持十进制和十六进制整数字面量(允许前导零)。
例如,0123-17009870xef0xEF0x0-0xfFAb0x0001-0-0x0 都是有效的数字字面量。

字符串字面量

FunC 中的字符串使用双引号 " 包裹,如 "this is a string"。不支持特殊符号如 \n 和多行字符串。 可选地,字符串字面量后可以指定类型,如 "string"u
支持以下字符串类型:
  • 无类型 —— 用于 asm 函数定义和通过 ASCII 字符串定义 slice 常量
  • s —— 通过其内容(十六进制编码并可选地位填充)定义原始 slice 常量
  • a —— 从指定地址创建包含 MsgAddressInt 结构的 slice 常量
  • u —— 创建对应于提供的 ASCII 字符串的十六进制值的 int 常量
  • h —— 创建字符串的 SHA256 哈希的前 32 位的 int 常量
  • H —— 创建字符串的 SHA256 哈希的所有 256 位的 int 常量
  • c —— 创建字符串的 crc32 值的 int 常量
例如,以下值会生成对应的常量:
  • "string" 变成 x{737472696e67} slice 常量
  • "abcdef"s 变成 x{abcdef} slice 常量
  • "Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a 变成 x{9FE6666666666666666666666666666666666666666666666666666666666666667_} slice 常量(addr_std$10 anycast:none$0 workchain_id:int8=0xFF address:bits256=0x33...33
  • "NstK"u 变成 0x4e73744b int 常量
  • "transfer(slice, int)"h 变成 0x7a62e8a8 int 常量
  • "transfer(slice, int)"H 变成 0x7a62e8a8ebac41bd6de16c65e7be363bc2d2cbc6a0873778dead4795c13db979 int 常量
  • "transfer(slice, int)"c 变成 2235694568 int 常量

1. 无类型(默认):

用于汇编函数定义定义 slice 常量,主要是将字符串按 ASCII 编码存储。例如,使用字符串表示指令或直接存储 ASCII 值的情况。
  • 场景:编写低级汇编代码或定义硬编码的字符串常量。
  • 示例"transfer" 用于表示某个硬编码的汇编指令。

2. s 类型

用于将字符串的十六进制编码值存储为 slice。可以选择对字符串进行位填充。
  • 场景:需要存储原始数据或进行位级别操作时,例如加密协议中,数据以十六进制形式存储或传递。
  • 示例"abcdef"s 将会存储为 x{abcdef}

3. a 类型

将字符串解释为一个地址,并生成一个包含 MsgAddressInt 结构的切片。这种类型用于处理区块链地址。
  • 场景:在区块链智能合约中操作和存储地址信息时使用。
  • 示例:从给定的地址创建一个标准格式的切片,用于指定消息的接收者地址。

4. u 类型

将 ASCII 字符串转换为其对应的十六进制整数值。这种转换方便在编译时处理字符串的数值表示。
  • 场景:需要快速计算字符串的十六进制值或需要用整数形式存储字符串时。
  • 示例"NstK"u 变为 0x4e73744b,ASCII 转换为整数常量。

5. h 类型

生成字符串的SHA256 哈希值的前 32 位,并将其存储为整数。这通常用于加密操作和哈希校验。
  • 场景:需要为较短的数据生成哈希摘要,以供后续加密操作或校验使用。
  • 示例"transfer(slice, int)"h 生成 0x7a62e8a8

6. H 类型

生成字符串的完整 256 位 SHA256 哈希值,并将其存储为整数。适用于全局唯一标识符或需要全哈希的场景。
  • 场景:需要完整哈希值时,尤其是在数据签名、哈希函数或密码学应用中使用。
  • 示例"transfer(slice, int)"H 生成 256 位 完整的 SHA256 哈希。

7. c 类型

计算字符串的crc32 校验值并将其存储为整数。这在数据完整性校验中常用。
  • 场景:需要快速验证数据完整性时,通常用于文件传输、校验和生成等场景。
  • 示例"transfer(slice, int)"c 生成 2235694568 的 crc32 校验值。

总结

这些类型标识符的使用主要集中在区块链合约加密操作低级编程等场景中,帮助开发者灵活处理和转换字符串,满足不同的存储、加密和校验需求。

标识符

FunC 允许使用非常广泛的标识符类别(函数和变量名)。具体来说,任何不包含特殊符号 ;,() (空格或制表符)、~ 和 .,不以注释或字符串字面量(以 " 开头)开始,不是数字字面量,不是下划线 _,也不是关键字的单行字符串都是有效的标识符(唯一的例外是,如果它以 ` 开头,则必须以相同的 ` 结尾,并且不能包含除这两个外的任何其他 `)。
此外,函数定义中的函数名可以以 . 或 ~ 开头。
例如,以下是有效的标识符:
  • queryquery'query''
  • elem0elem1elem2
  • CHECK
  • _internal_value
  • message_found?
  • get_pubkeys&signatures
  • dict::udict_set_builder
  • _+_(标准加法运算符,类型为 (int, int) -> int,虽然已被定义)
  • fatal!
变量名末尾的 ' 通常用于表示某个旧值的修改版本。例如,几乎所有用于 hashmap 操作的内置修改原语(除了以 ~ 为前缀的原语)都会接收一个 hashmap 并返回新版本的 hashmap 及必要时的其他数据。将这些值命名为相同名称后加 ' 很方便。
后缀 ? 通常用于布尔变量(TVM 没有内置的 bool 类型;bools 由整数表示:0 为 false,-1 为 true)或返回某些标志位的函数,通常表示操作的成功(如 stdlib.fc 中的 udict_get?)。
以下是无效的标识符:
  • take(first)Entry
  • "not_a_string
  • msg.sender
  • send_message,then_terminate
  • _
一些不太常见的有效标识符示例:
  • 123validname
  • 2+2=2*2
  • alsovalidname
  • 0xefefefhahaha
  • {hehehe}
  • pa{--}in"`aaa`"
这些也是无效的标识符:
  • pa;;in"`aaa`"(因为禁止使用 ;
  • {-aaa-}
  • aa(bb
  • 123(它是一个数字)
此外,FunC 有一种特殊类型的标识符,用反引号 ` 引用。 在引号内,任何符号都是允许的,除了 \n 和引号本身。
例如,`I'm a variable too` 是一个有效的标识符,`any symbols ; ~ () are allowed here...` 也是。

常量

FunC 允许定义编译时的常量,这些常量在编译期间被替换和预计算。
常量的定义格式为 const optional-type identifier = value-or-expression;
optional-type 可用于强制指定常量的特定类型,也用于更好的可读性。
目前,支持 int 和 slice 类型。
value-or-expression 可以是字面量或由字面量和常量组成的可预计算表达式。
例如,可以这样定义常量:
  • const int101 = 101; 定义等同于数字字面量 101 的 int101 常量
  • const str1 = "const1", str2 = "aabbcc"s; 定义两个等于其对应字符串的常量
  • const int int240 = ((int1 + int2) * 10) << 3; 定义等于计算结果的 int240 常量
  • const slice str2r = str2; 定义等于 str2 常量值的 str2r 常量
由于数字常量在编译期间被替换,所有在编译期间进行的优化和预计算都能成功执行(与旧方法通过内联 asm PUSHINT 定义常量不同)。