plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


plum-core/src/ast.rs
0a830c8 1
#[derive(Debug, Clone, PartialEq)]
0a830c8 2
pub struct Source {
0a830c8 3
    pub module: Option<Module>,
0a830c8 4
    pub imports: Vec<Import>,
0a830c8 5
    pub items: Vec<Item>,
0a830c8 6
}
0a830c8 7
0a830c8 8
#[derive(Debug, Clone, PartialEq)]
0a830c8 9
pub struct Module {
0a830c8 10
    pub name: String,
0a830c8 11
}
0a830c8 12
0a830c8 13
#[derive(Debug, Clone, PartialEq)]
0a830c8 14
pub struct Import {
0a830c8 15
    pub path: String,
0a830c8 16
}
0a830c8 17
0a830c8 18
#[derive(Debug, Clone, PartialEq)]
0a830c8 19
pub enum Item {
0a830c8 20
    Class(Class),
0a830c8 21
    Trait(Trait),
0a830c8 22
    Enum(Enum),
0a830c8 23
    Fn(Fn),
0a830c8 24
    Const(Const),
0a830c8 25
}
0a830c8 26
0a830c8 27
// ---------- Type definitions ----------
0a830c8 28
0a830c8 29
#[derive(Debug, Clone, PartialEq)]
0a830c8 30
pub struct Class {
0a830c8 31
    pub name: String,
0a830c8 32
    pub implements: Vec<String>,
0a830c8 33
    pub generics: Vec<GenericParam>,
0a830c8 34
    pub fields: Vec<Field>,
0a830c8 35
}
0a830c8 36
0a830c8 37
#[derive(Debug, Clone, PartialEq)]
0a830c8 38
pub struct GenericParam {
0a830c8 39
    pub name: String,
0a830c8 40
    pub bounds: Vec<String>,
0a830c8 41
}
0a830c8 42
0a830c8 43
#[derive(Debug, Clone, PartialEq)]
0a830c8 44
pub struct Field {
0a830c8 45
    pub name: String,
0a830c8 46
    pub ty: Type,
0a830c8 47
}
0a830c8 48
0a830c8 49
#[derive(Debug, Clone, PartialEq)]
0a830c8 50
pub struct Trait {
0a830c8 51
    pub name: String,
0a830c8 52
    pub generics: Vec<GenericParam>,
0a830c8 53
    pub methods: Vec<TraitMethod>,
0a830c8 54
}
0a830c8 55
0a830c8 56
#[derive(Debug, Clone, PartialEq)]
0a830c8 57
pub struct TraitMethod {
0a830c8 58
    pub name: String,
0a830c8 59
    pub params: Vec<Param>,
be16cd8 60
    pub returns: Option<Type>,
0a830c8 61
}
0a830c8 62
0a830c8 63
#[derive(Debug, Clone, PartialEq)]
0a830c8 64
pub struct Enum {
0a830c8 65
    pub name: String,
fbfbd7b 66
    pub params: Vec<EnumParam>,
0a830c8 67
    pub variants: Vec<EnumVariant>,
0a830c8 68
}
0a830c8 69
fbfbd7b 70
#[derive(Debug, Clone, PartialEq)]
fbfbd7b 71
pub struct EnumParam {
fbfbd7b 72
    pub name: String,
fbfbd7b 73
    pub ty: Type,
fbfbd7b 74
}
fbfbd7b 75
0a830c8 76
#[derive(Debug, Clone, PartialEq)]
0a830c8 77
pub struct EnumVariant {
0a830c8 78
    pub name: String,
0a830c8 79
    pub fields: Vec<String>,
fbfbd7b 80
    pub values: Vec<Expr>,
0a830c8 81
}
0a830c8 82
0a830c8 83
// ---------- Functions ----------
0a830c8 84
0a830c8 85
#[derive(Debug, Clone, PartialEq)]
0a830c8 86
pub struct Fn {
0a830c8 87
    pub name: String,
0a830c8 88
    /// Type parameter for method dispatch, e.g. `<Cat>` in `toStr<Cat>()`
0a830c8 89
    pub type_param: Option<String>,
0000000 90
    /// `extern fun foo(...)` — declares a function with no Plum body, backed
0000000 91
    /// instead by a host-provided wasm import (see `libs/std/os.plum`'s
0000000 92
    /// `printLn`). `plum-checker` requires this to agree with `body` being
0000000 93
    /// `FnBody::Extern`, and requires `type_param` to be `None` (no extern methods).
0000000 94
    pub is_extern: bool,
0a830c8 95
    pub params: Vec<Param>,
be16cd8 96
    pub returns: Option<Type>,
0a830c8 97
    pub body: FnBody,
0a830c8 98
}
0a830c8 99
0a830c8 100
#[derive(Debug, Clone, PartialEq)]
0a830c8 101
pub struct Const {
0a830c8 102
    pub name: String,
0a830c8 103
    pub value: Expr,
0a830c8 104
}
0a830c8 105
0a830c8 106
#[derive(Debug, Clone, PartialEq)]
0a830c8 107
pub struct Param {
0a830c8 108
    pub name: String,
0a830c8 109
    pub ty: ParamType,
0a830c8 110
    pub default: Option<Expr>,
0a830c8 111
}
0a830c8 112
0a830c8 113
#[derive(Debug, Clone, PartialEq)]
0a830c8 114
pub enum ParamType {
0a830c8 115
    Type(Type),
0a830c8 116
    Variadic(Type),
d7e5ff4 117
    /// `fn(Int, Str) -> Bool` — a function-value type annotation. Positional types
d7e5ff4 118
    /// only, no param names (types don't need names).
d7e5ff4 119
    Fn(Vec<Type>, Option<Box<Type>>),
0a830c8 120
}
0a830c8 121
0a830c8 122
#[derive(Debug, Clone, PartialEq)]
0a830c8 123
pub struct Type {
0a830c8 124
    pub name: String,
0a830c8 125
    pub generics: Vec<Type>,
0a830c8 126
}
0a830c8 127
0a830c8 128
#[derive(Debug, Clone, PartialEq)]
0a830c8 129
pub enum FnBody {
0a830c8 130
    Expr(Expr),
0a830c8 131
    Block(Block),
0000000 132
    /// No body was written at all — valid only paired with `Fn.is_extern`
0000000 133
    /// (`plum-checker` rejects any other combination).
0000000 134
    Extern,
0a830c8 135
}
0a830c8 136
0a830c8 137
// ---------- Statements ----------
0a830c8 138
0a830c8 139
#[derive(Debug, Clone, PartialEq)]
0a830c8 140
pub struct Block {
0a830c8 141
    pub stmts: Vec<Stmt>,
0a830c8 142
}
0a830c8 143
d7e5ff4 144
#[derive(Debug, Clone, PartialEq)]
d7e5ff4 145
pub struct Closure {
d7e5ff4 146
    pub params: Vec<String>,
d7e5ff4 147
    pub body: Block,
d7e5ff4 148
}
d7e5ff4 149
0a830c8 150
#[derive(Debug, Clone, PartialEq)]
0a830c8 151
pub enum Stmt {
0a830c8 152
    Assign(Assign),
0a830c8 153
    Break,
0a830c8 154
    Continue,
0a830c8 155
    Assert(Expr),
0a830c8 156
    For(For),
0a830c8 157
    While(While),
0a830c8 158
    If(If),
0a830c8 159
    Match(Match),
0a830c8 160
    Return(Option<Expr>),
0a830c8 161
    Todo,
0a830c8 162
    Expr(Expr),
0a830c8 163
}
0a830c8 164
3d79c9f 165
#[derive(Debug, Clone, PartialEq)]
3d79c9f 166
pub enum AssignTarget {
3d79c9f 167
    Var(String),
3d79c9f 168
    /// `object.field = value` — `object`'s evaluated type must be a class; `field`
3d79c9f 169
    /// is that class's field name being written.
3d79c9f 170
    Field(Box<Expr>, String),
3d79c9f 171
}
3d79c9f 172
0a830c8 173
#[derive(Debug, Clone, PartialEq)]
0a830c8 174
pub struct Assign {
3d79c9f 175
    pub targets: Vec<AssignTarget>,
0a830c8 176
    pub values: Vec<Expr>,
0000000 177
    /// `true` for `x := 5` (declares `x`, inferring its type from `value`);
0000000 178
    /// `false` for `x = 5` (requires `x` already declared, with a type matching
0000000 179
    /// `value`'s — a compile error otherwise, like Go's `:=`/`=` distinction).
0000000 180
    pub declare: bool,
0a830c8 181
}
0a830c8 182
0a830c8 183
#[derive(Debug, Clone, PartialEq)]
0a830c8 184
pub struct For {
0a830c8 185
    pub vars: Vec<String>,
0a830c8 186
    pub iter: Expr,
0a830c8 187
    pub body: Block,
0a830c8 188
}
0a830c8 189
0a830c8 190
#[derive(Debug, Clone, PartialEq)]
0a830c8 191
pub struct While {
0a830c8 192
    pub condition: Expr,
0a830c8 193
    pub body: Block,
0a830c8 194
}
0a830c8 195
0a830c8 196
#[derive(Debug, Clone, PartialEq)]
0a830c8 197
pub struct If {
0a830c8 198
    pub condition: Expr,
0a830c8 199
    pub body: Block,
0a830c8 200
    pub else_ifs: Vec<ElseIf>,
0a830c8 201
    pub else_: Option<Block>,
0a830c8 202
}
0a830c8 203
0a830c8 204
#[derive(Debug, Clone, PartialEq)]
0a830c8 205
pub struct ElseIf {
0a830c8 206
    pub condition: Expr,
0a830c8 207
    pub body: Block,
0a830c8 208
}
0a830c8 209
0a830c8 210
#[derive(Debug, Clone, PartialEq)]
0a830c8 211
pub struct Match {
0a830c8 212
    pub subjects: Vec<Expr>,
0a830c8 213
    pub cases: Vec<Case>,
0a830c8 214
}
0a830c8 215
0a830c8 216
#[derive(Debug, Clone, PartialEq)]
0a830c8 217
pub struct Case {
0a830c8 218
    pub patterns: Vec<CasePattern>,
0a830c8 219
    pub body: Block,
0a830c8 220
}
0a830c8 221
0a830c8 222
#[derive(Debug, Clone, PartialEq)]
0a830c8 223
pub enum CasePattern {
0a830c8 224
    Class { name: String, fields: Vec<CasePattern> },
0a830c8 225
    String(String),
0a830c8 226
    Int(i64),
0a830c8 227
    Float(f64),
0a830c8 228
    Name(String),
0a830c8 229
    Wildcard,
0a830c8 230
}
0a830c8 231
0a830c8 232
// ---------- Expressions ----------
0a830c8 233
0a830c8 234
/// Expressions are the core of the language. Operator precedence is already
0a830c8 235
/// resolved by the tree-sitter parser (via the PREC table in grammar.js), so
0a830c8 236
/// the tree structure here directly reflects evaluation order.
0a830c8 237
#[derive(Debug, Clone, PartialEq)]
0a830c8 238
pub enum Expr {
0a830c8 239
    /// Arithmetic / bitwise / range: `a + b`, `a .. b`, etc.
0a830c8 240
    Binary(Box<BinaryExpr>),
0a830c8 241
    /// Prefix `+` or `-`
0a830c8 242
    Unary(Box<UnaryExpr>),
0a830c8 243
    /// `&&` / `||`
0a830c8 244
    Bool(Box<BoolExpr>),
0a830c8 245
    /// `!expr`
0a830c8 246
    Not(Box<Expr>),
0a830c8 247
    /// `<`, `<=`, `==`, `!=`, `>=`, `>`, `<>`
0a830c8 248
    Compare(Box<CompareExpr>),
0a830c8 249
    /// `cond ? then : else`
0a830c8 250
    Ternary(Box<TernaryExpr>),
0a830c8 251
    /// `fnName(args…)`
0a830c8 252
    FnCall(FnCall),
0a830c8 253
    /// `TypeName(field: value, …)`
0a830c8 254
    ClassCall(ClassCall),
0a830c8 255
    /// `expr.field` or `expr.method(…)`
0a830c8 256
    Attribute(Box<AttributeExpr>),
0a830c8 257
    /// `{expr}` — grouped/parenthesized expression
0a830c8 258
    Paren(Box<Expr>),
0a830c8 259
    String(StringExpr),
0a830c8 260
    Int(i64),
0a830c8 261
    Float(f64),
0a830c8 262
    Self_,
0a830c8 263
    Var(String),
0a830c8 264
    TypeName(String),
d7e5ff4 265
    /// `|params| body`
d7e5ff4 266
    Closure(Box<Closure>),
0a830c8 267
}
0a830c8 268
0a830c8 269
#[derive(Debug, Clone, PartialEq)]
0a830c8 270
pub struct BinaryExpr {
0a830c8 271
    pub op: BinOp,
0a830c8 272
    pub left: Expr,
0a830c8 273
    pub right: Expr,
0a830c8 274
}
0a830c8 275
0a830c8 276
#[derive(Debug, Clone, PartialEq)]
0a830c8 277
pub enum BinOp {
0a830c8 278
    Add,
0a830c8 279
    Sub,
0a830c8 280
    Mul,
0a830c8 281
    Div,
0a830c8 282
    Mod,
0a830c8 283
    BitOr,
0a830c8 284
    BitAnd,
0a830c8 285
    Xor,
0a830c8 286
    Shl,
0a830c8 287
    Shr,
0a830c8 288
}
0a830c8 289
0a830c8 290
#[derive(Debug, Clone, PartialEq)]
0a830c8 291
pub struct UnaryExpr {
0a830c8 292
    pub op: UnOp,
0a830c8 293
    pub operand: Expr,
0a830c8 294
}
0a830c8 295
0a830c8 296
#[derive(Debug, Clone, PartialEq)]
0a830c8 297
pub enum UnOp {
0a830c8 298
    Pos,
0a830c8 299
    Neg,
0a830c8 300
}
0a830c8 301
0a830c8 302
#[derive(Debug, Clone, PartialEq)]
0a830c8 303
pub struct BoolExpr {
0a830c8 304
    pub op: BoolOp,
0a830c8 305
    pub left: Expr,
0a830c8 306
    pub right: Expr,
0a830c8 307
}
0a830c8 308
0a830c8 309
#[derive(Debug, Clone, PartialEq)]
0a830c8 310
pub enum BoolOp {
0a830c8 311
    And,
0a830c8 312
    Or,
0a830c8 313
}
0a830c8 314
0a830c8 315
#[derive(Debug, Clone, PartialEq)]
0a830c8 316
pub struct CompareExpr {
0a830c8 317
    pub op: CmpOp,
0a830c8 318
    pub left: Expr,
0a830c8 319
    pub right: Expr,
0a830c8 320
}
0a830c8 321
0a830c8 322
#[derive(Debug, Clone, PartialEq)]
0a830c8 323
pub enum CmpOp {
0a830c8 324
    Lt,
0a830c8 325
    Lte,
0a830c8 326
    Eq,
0a830c8 327
    Neq,
0a830c8 328
    Gte,
0a830c8 329
    Gt,
0a830c8 330
    NotEq2,
0a830c8 331
}
0a830c8 332
0a830c8 333
#[derive(Debug, Clone, PartialEq)]
0a830c8 334
pub struct TernaryExpr {
0a830c8 335
    pub condition: Expr,
0a830c8 336
    pub then: Expr,
0a830c8 337
    pub else_: Expr,
0a830c8 338
}
0a830c8 339
0a830c8 340
#[derive(Debug, Clone, PartialEq)]
0a830c8 341
pub struct FnCall {
0a830c8 342
    pub name: String,
0a830c8 343
    pub args: Vec<Arg>,
0a830c8 344
}
0a830c8 345
0a830c8 346
#[derive(Debug, Clone, PartialEq)]
0a830c8 347
pub enum Arg {
0a830c8 348
    Positional(Expr),
0a830c8 349
    Keyword { name: String, value: Expr },
0a830c8 350
    Pair { key: String, value: Expr },
0a830c8 351
}
0a830c8 352
0a830c8 353
#[derive(Debug, Clone, PartialEq)]
0a830c8 354
pub struct ClassCall {
0a830c8 355
    pub type_name: String,
0a830c8 356
    pub fields: Vec<FieldArg>,
0000000 357
    /// Explicit type arguments (`List[Int](...)`) — empty unless the source
0000000 358
    /// actually wrote a `[...]` generics clause. Needed whenever a generic
0000000 359
    /// class's own field VALUES can't pin down its type params on their own
0000000 360
    /// (e.g. constructing an empty `List` with nothing to infer `T` from).
0000000 361
    pub generics: Vec<Type>,
0a830c8 362
}
0a830c8 363
0a830c8 364
#[derive(Debug, Clone, PartialEq)]
0a830c8 365
pub struct FieldArg {
0a830c8 366
    pub name: String,
0a830c8 367
    pub value: Expr,
0a830c8 368
}
0a830c8 369
0a830c8 370
#[derive(Debug, Clone, PartialEq)]
0a830c8 371
pub struct AttributeExpr {
0a830c8 372
    pub object: Expr,
0a830c8 373
    pub attr: AttrKind,
0a830c8 374
}
0a830c8 375
0a830c8 376
#[derive(Debug, Clone, PartialEq)]
0a830c8 377
pub enum AttrKind {
0a830c8 378
    Field(String),
0a830c8 379
    Method(FnCall),
0a830c8 380
}
0a830c8 381
0a830c8 382
#[derive(Debug, Clone, PartialEq)]
0a830c8 383
pub struct StringExpr {
0a830c8 384
    pub parts: Vec<StringPart>,
0a830c8 385
}
0a830c8 386
0a830c8 387
#[derive(Debug, Clone, PartialEq)]
0a830c8 388
pub enum StringPart {
0a830c8 389
    Text(String),
0a830c8 390
    Interp(Expr),
0a830c8 391
}