plum
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 | } |