Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

语言参考手册

本文档是 Cavvy(Cay)编程语言的完整语法和语义参考。

版本说明:本文档按 6.1.0 语义维护;5.2.0~5.4.0 的迁移背景见版本演进总览


词法结构

注释

// 单行注释

/* 多行
   注释 */

关键字

class, interface, struct, enum, extends, implements
public, private, protected, static, final, abstract, native
if, else, switch, case, default, for, while, do, break, continue, return
new, delete, this, super, instanceof, typeof
true, false, null
var, void, int, long, float, double, bool, boolean, char, string
try, catch, finally, throw
namespace, using, import, extern, alias, typedef
virtual, override, synchronized, const, mutable, volatile

字面量

public class Main {
    public static void main() {
        int a = 42;
        int b = 0xFF;
        int c = 0b1010;
        double d = 3.14;
        float e = 3.14f;
        char f = 'A';
        string g = "hello";
        bool h = true;
        println(String.valueOf(a + b + c));
        println(g);
    }
}

类型系统

基本类型

类型位数描述默认值
void0无返回值
int / i3232有符号整数0
long / i6464有符号整数0L
float / f3232IEEE 754 浮点数0.0f
double / f6464IEEE 754 浮点数0.0
bool / boolean8布尔值false
char16UTF-16 字符‘\0’
string / String不可变字符串null

注意i32i64f32f64 是类型关键字的别名,不能用作标识符(如变量名、类型别名名)。例如 alias i32 = int; 是非法的,应使用 alias MyInt = int;

复合类型

类型语法说明
数组T[]动态长度数组
指针T*FFI 使用的 C 风格指针
函数指针fn(T1, T2) -> R函数签名类型
类引用ClassName堆分配的对象引用
接口引用InterfaceName运行时多态引用

FFI 类型

#include "std/ffi.cay"

public class Main {
    public static void main() {
        // FFI 类型: c_char, c_uchar, c_short, c_ushort
        // c_int, c_uint, c_long, c_ulong
        // c_float, c_double, c_void, c_bool
        // size_t, ssize_t, uintptr_t, intptr_t
        // c_string — C 风格字符串 (char*)
        c_string msg = "Hello";
        println("ffi types ok");
    }
}

alias

创建类型别名:

alias MyInt = int;

class Main {
    public static void main() {
        MyInt a = 1;
        print(a);
    }
}

Result 与错误传播(6.1.0)

Result<T, E> 表示成功值或错误值,两个类型参数都必须显式给出:

Result<int, String> ok = Result<int, String>.ok(42);
Result<int, String> failed = Result<int, String>.err("invalid input");

if (ok.isOk()) {
    println(String.valueOf(ok.unwrap()));
}
int fallback = failed.unwrapOr(0);

可用操作包括 okerrisOkisErrunwrapunwrapOrunwrapErrexpectexpectunwrapunwrapErr 不应替代可恢复错误分支。

函数返回兼容的 Result 时,可以使用 ? 传播错误:

public Result<int, String> readValue() {
    Result<int, String> value = Result<int, String>.ok(7);
    int number = value?;
    return Result<int, String>.ok(number + 1);
}

智能指针与 RAII(5.3.0)

标准库提供四种所有权模型:UniquePtr<T>(独占且可转移)、ScopedPtr<T>(作用域独占)、Rc<T>(共享引用计数)和 WeakPtr<T>(弱引用)。作用域退出时,编译器会为受支持对象注入析构调用。

UniquePtr<Node> node = UniquePtr<Node>.fromRaw(new Node());
Node borrowed = node.get();
Node owned = node.release();

release() 会放弃托管权,调用方随后负责对象生命周期;不要在智能指针仍持有对象时手动释放同一对象。

内存映射文件(5.4.0)

Mmap 支持 Windows 和 Linux 的只读/读写映射,MmapSlice 是零拷贝视图:

MmapResult<Mmap> result = Mmap.mapReadOnly("data.bin");
if (result.isOk()) {
    Mmap mapped = result.unwrap();
    MmapSlice bytes = mapped.slice(0, mapped.size());
    // 使用 bytes 后再 unmap mapped
    mapped.unmap();
}

写映射完成后调用 sync()。映射失败、偏移越界以及 unmap() 后继续使用切片都是错误情况,应由调用方处理。


顶层声明

源文件的顶层允许以下声明:

class, struct, enum, interface
extern block
namespace { ... }
using path::Name;
alias type = existing_type;
#include (预处理指令)
顶层函数(`public int main()`)

访问修饰符

修饰符描述
public任何地方可访问
private仅当前类内部访问
protected类及其子类可访问
(无修饰符)包/模块内部访问

注意private 访问修饰符在语义分析中已定义,但编译器尚未强制执行 private 访问控制。

其他修饰符

修饰符用途
static静态成员(属于类而非实例)
final类:禁止继承;方法:禁止重写
abstract抽象类(不可实例化)或抽象方法
nativenative 方法声明(由 FFI 实现)
virtual可被重写的虚方法
override重写父类方法

类定义

class ClassName {
    // 字段
    // 方法
    // 构造函数
    // 析构函数
}

构造函数

class Point {
    int x;
    int y;

    // 无参构造函数
    Point() {
        x = 0;
        y = 0;
    }

    // 带参构造函数
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // 委托构造函数
    Point(int val) : this(val, val) {}
}

析构函数

class Resource {
    int* data;

    Resource() {
        data = new int[1024];
    }

    ~Resource() {
        delete[] data;
    }
}

继承

public class Animal {
    public String name;

    public Animal(String name) {
        this.name = name;
    }

    public void speak() {
        println("...");
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void speak() {
        super.speak();
        println("汪汪!");
    }
}

抽象类

public abstract class Shape {
    public abstract double area();
    public abstract double perimeter();
}

public class Circle extends Shape {
    public double radius;

    public Circle(double r) { radius = r; }

    @Override
    public double area() {
        return 3.14159 * radius * radius;
    }

    @Override
    public double perimeter() {
        return 2.0 * 3.14159 * radius;
    }
}

public class Main {
    public static void main() {
        Circle c = new Circle(5.0);
        println(String.valueOf(c.area()));
    }
}

接口

public interface Flyable {
    void fly();
    void land();
}

public class Bird implements Flyable {
    public void fly() { println("Flying..."); }
    public void land() { println("Landing..."); }
}

public class Main {
    public static void main() {
        Flyable f = new Bird();
        f.fly();
    }
}

关键实现细节

  • 接口调用通过对象 vtable 运行时分发
  • 支持多个实现类共享同一接口类型
  • a1.speak() 按运行时类型调用正确的方法实现

结构体

值类型,栈分配:

public struct Point {
    public int x;
    public int y;

    public int sum() {
        return x + y;
    }
}

public class Main {
    public static void main() {
        Point p = new Point();
        p.x = 10;
        p.y = 20;
        int s = p.sum();
        println(String.valueOf(s));
    }
}

枚举

public enum Color {
    Red,
    Green,
    Blue
}

public class Main {
    public static void main() {
        Color c = Color.Red;
        println("enum ok");
    }
}

Namespace

class Main {
    public static void main() {
        println("namespace organizes code");
    }
}

泛型

public class Box<T> {
    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T get() {
        return this.value;
    }
}

public class Main {
    public static void main() {
        Box<int> intBox = new Box<int>(42);
        println(String.valueOf(intBox.get()));
    }
}

注意:泛型语法已解析,但代码生成尚未实现单态化。泛型类可以在代码中编写,但尚不能正确编译为机器码。


Lambda 表达式

public class Main {
    public static void main() {
        var add = (int a, int b) -> a + b;
        var funcPtr = add;
        int r = funcPtr(3, 4);
        println(String.valueOf(r));
    }
}

注意:Lambda 闭包捕获环境变量尚未完整实现


数组

一维数组

public class Main {
    public static void main() {
        int[] arr = new int[10];
        arr[0] = 42;
        int len = arr.length();
        println(String.valueOf(len));
    }
}

数组初始化

public class Main {
    public static void main() {
        int[] arr = new int[3];
        arr[0] = 1;
        arr[1] = 2;
        arr[2] = 3;
        println(String.valueOf(arr[0] + arr[1] + arr[2]));
    }
}

字符串

字符串方法

public class Main {
    public static void main() {
        string s = "Hello, Cavvy!";
        int len = s.length();
        string up = s.toUpperCase();
        println(String.valueOf(len));
        println(up);
    }
}

字符串连接

public class Main {
    public static void main() {
        string name = "Cavvy";
        string greeting = "Hello, " + name + "!";
        println(greeting);
    }
}

控制流

if-else

public class Main {
    public static void main() {
        int x = 5;
        if (x > 0) {
            println("positive");
        } else if (x == 0) {
            println("zero");
        } else {
            println("negative");
        }
    }
}

switch

public class Main {
    public static void main() {
        int value = 2;
        switch (value) {
            case 1:
                println("one");
                break;
            case 2:
            case 3:
                println("two or three");
                break;
            default:
                println("other");
                break;
        }
    }
}

for 循环

public class Main {
    public static void main() {
        for (int i = 0; i < 3; i = i + 1) {
            println(String.valueOf(i));
        }
    }
}

while 循环

public class Main {
    public static void main() {
        int i = 0;
        while (i < 3) {
            println(String.valueOf(i));
            i = i + 1;
        }
    }
}

do-while 循环

public class Main {
    public static void main() {
        int i = 0;
        do {
            println(String.valueOf(i));
            i = i + 1;
        } while (i < 3);
    }
}

跳转语句

public class Main {
    public static void main() {
        for (int i = 0; i < 5; i = i + 1) {
            if (i == 0) continue;
            if (i == 3) break;
            println(String.valueOf(i));
        }
    }
}

异常处理

public class Main {
    public static void main() {
        println("exception handling with try/catch/finally");
    }
}

注解


public class Main {
    @FreeFunction
    public String toString() {
        return "annotations demo";
    }

    public static void main() {
        println(toString());
    }
}

预处理器指令

详见预处理器文档

#include <File.cay>
#define MACRO value
#ifdef CONDITION
#endif
#pragma once
// #error "message"

内联 IR

__ir { ... } 可在函数或方法体内插入 LLVM IR 指令,包括 public/private、static/instance 方法以及顶层函数。private 方法同样允许使用内联 IR;这不会收窄其他可用场景。

public class Main {
    private static int addOne(int x) {
        int result;
        __ir {
            %sum = add i32 %x, 1
            store i32 %sum, i32* %result
        }
        return result;
    }
}

内联 IR 可以引用当前作用域中的 Cavvy 变量,形式为 %变量名,也可以用 %0%1 等按参数和局部变量顺序引用。该功能面向底层库和性能敏感代码,使用者需要保证 IR 类型和控制流正确。


FFI extern 声明

详见 FFI 文档

extern {
    void* malloc(size_t size);
    void free(void* ptr);
    int printf(c_string fmt, ...);
}

// 调用约定指定
extern "stdcall" {
    // ...
}

完整语法(EBNF)

完整的 Cavvy 形式化语法定义在项目根目录的 cavvy.ebnf 文件中,涵盖:

  • 预处理器指令
  • 类型表达式
  • 类、接口、结构体、枚举定义
  • 方法声明和语句
  • 各类表达式
  • 字面量和运算符优先级