Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
3cb85c7f42 |
@ -2,7 +2,6 @@
|
|||||||
members = [
|
members = [
|
||||||
"compiler/cl-repl",
|
"compiler/cl-repl",
|
||||||
"compiler/cl-typeck",
|
"compiler/cl-typeck",
|
||||||
"compiler/cl-embed",
|
|
||||||
"compiler/cl-interpret",
|
"compiler/cl-interpret",
|
||||||
"compiler/cl-structures",
|
"compiler/cl-structures",
|
||||||
"compiler/cl-token",
|
"compiler/cl-token",
|
||||||
@ -17,7 +16,7 @@ resolver = "2"
|
|||||||
repository = "https://git.soft.fish/j/Conlang"
|
repository = "https://git.soft.fish/j/Conlang"
|
||||||
version = "0.0.9"
|
version = "0.0.9"
|
||||||
authors = ["John Breaux <j@soft.fish>"]
|
authors = ["John Breaux <j@soft.fish>"]
|
||||||
edition = "2024"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
publish = ["soft-fish"]
|
publish = ["soft-fish"]
|
||||||
|
|
||||||
|
@ -31,10 +31,19 @@ pub enum Visibility {
|
|||||||
Public,
|
Public,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [Literal]: 0x42, 1e123, 2.4, "Hello"
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Literal {
|
||||||
|
Bool(bool),
|
||||||
|
Char(char),
|
||||||
|
Int(u128),
|
||||||
|
Float(u64),
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
/// A list of [Item]s
|
/// A list of [Item]s
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub name: &'static str,
|
|
||||||
pub items: Vec<Item>,
|
pub items: Vec<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +72,7 @@ pub enum MetaKind {
|
|||||||
/// Anything that can appear at the top level of a [File]
|
/// Anything that can appear at the top level of a [File]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub span: Span,
|
pub extents: Span,
|
||||||
pub attrs: Attrs,
|
pub attrs: Attrs,
|
||||||
pub vis: Visibility,
|
pub vis: Visibility,
|
||||||
pub kind: ItemKind,
|
pub kind: ItemKind,
|
||||||
@ -93,23 +102,10 @@ pub enum ItemKind {
|
|||||||
Use(Use),
|
Use(Use),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of type variables to introduce
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Generics {
|
|
||||||
pub vars: Vec<Sym>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An ordered collection of [Items](Item)
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Module {
|
|
||||||
pub name: Sym,
|
|
||||||
pub file: Option<File>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An alias to another [Ty]
|
/// An alias to another [Ty]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Alias {
|
pub struct Alias {
|
||||||
pub name: Sym,
|
pub to: Sym,
|
||||||
pub from: Option<Box<Ty>>,
|
pub from: Option<Box<Ty>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,21 +126,40 @@ pub struct Static {
|
|||||||
pub init: Box<Expr>,
|
pub init: Box<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An ordered collection of [Items](Item)
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Module {
|
||||||
|
pub name: Sym,
|
||||||
|
pub kind: ModuleKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The contents of a [Module], if they're in the same file
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ModuleKind {
|
||||||
|
Inline(File),
|
||||||
|
Outline,
|
||||||
|
}
|
||||||
|
|
||||||
/// Code, and the interface to that code
|
/// Code, and the interface to that code
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub name: Sym,
|
pub name: Sym,
|
||||||
pub gens: Generics,
|
|
||||||
pub sign: TyFn,
|
pub sign: TyFn,
|
||||||
pub bind: Pattern,
|
pub bind: Vec<Param>,
|
||||||
pub body: Option<Expr>,
|
pub body: Option<Block>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A single parameter for a [Function]
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Param {
|
||||||
|
pub mutability: Mutability,
|
||||||
|
pub name: Sym,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A user-defined product type
|
/// A user-defined product type
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Struct {
|
pub struct Struct {
|
||||||
pub name: Sym,
|
pub name: Sym,
|
||||||
pub gens: Generics,
|
|
||||||
pub kind: StructKind,
|
pub kind: StructKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,16 +183,31 @@ pub struct StructMember {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Enum {
|
pub struct Enum {
|
||||||
pub name: Sym,
|
pub name: Sym,
|
||||||
pub gens: Generics,
|
pub kind: EnumKind,
|
||||||
pub variants: Vec<Variant>,
|
}
|
||||||
|
|
||||||
|
/// An [Enum]'s [Variant]s, if it has a variant block
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum EnumKind {
|
||||||
|
/// Represents an enum with no variants
|
||||||
|
NoVariants,
|
||||||
|
Variants(Vec<Variant>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single [Enum] variant
|
/// A single [Enum] variant
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Variant {
|
pub struct Variant {
|
||||||
pub name: Sym,
|
pub name: Sym,
|
||||||
pub kind: StructKind,
|
pub kind: VariantKind,
|
||||||
pub body: Option<Box<Expr>>,
|
}
|
||||||
|
|
||||||
|
/// Whether the [Variant] has a C-like constant value, a tuple, or [StructMember]s
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum VariantKind {
|
||||||
|
Plain,
|
||||||
|
CLike(u128),
|
||||||
|
Tuple(Ty),
|
||||||
|
Struct(Vec<StructMember>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sub-[items](Item) (associated functions, etc.) for a [Ty]
|
/// Sub-[items](Item) (associated functions, etc.) for a [Ty]
|
||||||
@ -214,7 +244,7 @@ pub enum UseTree {
|
|||||||
/// A type expression
|
/// A type expression
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Ty {
|
pub struct Ty {
|
||||||
pub span: Span,
|
pub extents: Span,
|
||||||
pub kind: TyKind,
|
pub kind: TyKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +253,6 @@ pub struct Ty {
|
|||||||
pub enum TyKind {
|
pub enum TyKind {
|
||||||
Never,
|
Never,
|
||||||
Empty,
|
Empty,
|
||||||
Infer,
|
|
||||||
Path(Path),
|
Path(Path),
|
||||||
Array(TyArray),
|
Array(TyArray),
|
||||||
Slice(TySlice),
|
Slice(TySlice),
|
||||||
@ -256,7 +285,7 @@ pub struct TyTuple {
|
|||||||
pub struct TyRef {
|
pub struct TyRef {
|
||||||
pub mutable: Mutability,
|
pub mutable: Mutability,
|
||||||
pub count: u16,
|
pub count: u16,
|
||||||
pub to: Box<Ty>,
|
pub to: Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The args and return value for a function pointer [Ty]pe
|
/// The args and return value for a function pointer [Ty]pe
|
||||||
@ -277,6 +306,7 @@ pub struct Path {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum PathPart {
|
pub enum PathPart {
|
||||||
SuperKw,
|
SuperKw,
|
||||||
|
SelfKw,
|
||||||
SelfTy,
|
SelfTy,
|
||||||
Ident(Sym),
|
Ident(Sym),
|
||||||
}
|
}
|
||||||
@ -284,7 +314,7 @@ pub enum PathPart {
|
|||||||
/// An abstract statement, and associated metadata
|
/// An abstract statement, and associated metadata
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Stmt {
|
pub struct Stmt {
|
||||||
pub span: Span,
|
pub extents: Span,
|
||||||
pub kind: StmtKind,
|
pub kind: StmtKind,
|
||||||
pub semi: Semi,
|
pub semi: Semi,
|
||||||
}
|
}
|
||||||
@ -307,7 +337,7 @@ pub enum Semi {
|
|||||||
/// An expression, the beating heart of the language
|
/// An expression, the beating heart of the language
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Expr {
|
pub struct Expr {
|
||||||
pub span: Span,
|
pub extents: Span,
|
||||||
pub kind: ExprKind,
|
pub kind: ExprKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,28 +347,12 @@ pub enum ExprKind {
|
|||||||
/// An empty expression: `(` `)`
|
/// An empty expression: `(` `)`
|
||||||
#[default]
|
#[default]
|
||||||
Empty,
|
Empty,
|
||||||
/// A [Closure] expression: `|` [`Expr`] `|` ( -> [`Ty`])? [`Expr`]
|
|
||||||
Closure(Closure),
|
|
||||||
/// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
|
|
||||||
Tuple(Tuple),
|
|
||||||
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
|
||||||
Structor(Structor),
|
|
||||||
/// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]`
|
|
||||||
Array(Array),
|
|
||||||
/// An Array literal constructed with [repeat syntax](ArrayRep)
|
|
||||||
/// `[` [Expr] `;` [Literal] `]`
|
|
||||||
ArrayRep(ArrayRep),
|
|
||||||
/// An address-of expression: `&` `mut`? [`Expr`]
|
|
||||||
AddrOf(AddrOf),
|
|
||||||
/// A backtick-quoted expression
|
/// A backtick-quoted expression
|
||||||
Quote(Quote),
|
Quote(Quote),
|
||||||
/// A [Literal]: 0x42, 1e123, 2.4, "Hello"
|
/// A local bind instruction, `let` [`Sym`] `=` [`Expr`]
|
||||||
Literal(Literal),
|
Let(Let),
|
||||||
/// A [Grouping](Group) expression `(` [`Expr`] `)`
|
/// A [Match] expression: `match` [Expr] `{` ([MatchArm] `,`)* [MatchArm]? `}`
|
||||||
Group(Group),
|
Match(Match),
|
||||||
/// A [Block] expression: `{` [`Stmt`]\* [`Expr`]? `}`
|
|
||||||
Block(Block),
|
|
||||||
|
|
||||||
/// An [Assign]ment expression: [`Expr`] (`=` [`Expr`])\+
|
/// An [Assign]ment expression: [`Expr`] (`=` [`Expr`])\+
|
||||||
Assign(Assign),
|
Assign(Assign),
|
||||||
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
||||||
@ -347,23 +361,36 @@ pub enum ExprKind {
|
|||||||
Binary(Binary),
|
Binary(Binary),
|
||||||
/// A [Unary] expression: [`UnaryKind`]\* [`Expr`]
|
/// A [Unary] expression: [`UnaryKind`]\* [`Expr`]
|
||||||
Unary(Unary),
|
Unary(Unary),
|
||||||
|
/// A [Cast] expression: [`Expr`] `as` [`Ty`]
|
||||||
|
Cast(Cast),
|
||||||
/// A [Member] access expression: [`Expr`] [`MemberKind`]\*
|
/// A [Member] access expression: [`Expr`] [`MemberKind`]\*
|
||||||
Member(Member),
|
Member(Member),
|
||||||
/// An Array [Index] expression: a[10, 20, 30]
|
/// An Array [Index] expression: a[10, 20, 30]
|
||||||
Index(Index),
|
Index(Index),
|
||||||
/// A [Cast] expression: [`Expr`] `as` [`Ty`]
|
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
||||||
Cast(Cast),
|
Structor(Structor),
|
||||||
/// A [path expression](Path): `::`? [PathPart] (`::` [PathPart])*
|
/// A [path expression](Path): `::`? [PathPart] (`::` [PathPart])*
|
||||||
Path(Path),
|
Path(Path),
|
||||||
/// A local bind instruction, `let` [`Sym`] `=` [`Expr`]
|
/// A [Literal]: 0x42, 1e123, 2.4, "Hello"
|
||||||
Let(Let),
|
Literal(Literal),
|
||||||
/// A [Match] expression: `match` [Expr] `{` ([MatchArm] `,`)* [MatchArm]? `}`
|
/// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]`
|
||||||
Match(Match),
|
Array(Array),
|
||||||
|
/// An Array literal constructed with [repeat syntax](ArrayRep)
|
||||||
|
/// `[` [Expr] `;` [Literal] `]`
|
||||||
|
ArrayRep(ArrayRep),
|
||||||
|
/// An address-of expression: `&` `mut`? [`Expr`]
|
||||||
|
AddrOf(AddrOf),
|
||||||
|
/// A [Block] expression: `{` [`Stmt`]\* [`Expr`]? `}`
|
||||||
|
Block(Block),
|
||||||
|
/// A [Grouping](Group) expression `(` [`Expr`] `)`
|
||||||
|
Group(Group),
|
||||||
|
/// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
|
||||||
|
Tuple(Tuple),
|
||||||
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
|
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
|
||||||
While(While),
|
While(While),
|
||||||
/// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]?
|
/// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]?
|
||||||
If(If),
|
If(If),
|
||||||
/// A [For] expression: `for` [`Pattern`] `in` [`Expr`] [`Block`] [`Else`]?
|
/// A [For] expression: `for` Pattern `in` [`Expr`] [`Block`] [`Else`]?
|
||||||
For(For),
|
For(For),
|
||||||
/// A [Break] expression: `break` [`Expr`]?
|
/// A [Break] expression: `break` [`Expr`]?
|
||||||
Break(Break),
|
Break(Break),
|
||||||
@ -373,100 +400,54 @@ pub enum ExprKind {
|
|||||||
Continue,
|
Continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Closure [expression](Expr): `|` [`Expr`] `|` ( -> [`Ty`])? [`Expr`]
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Closure {
|
|
||||||
pub arg: Box<Pattern>,
|
|
||||||
pub body: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Tuple {
|
|
||||||
pub exprs: Vec<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Structor {
|
|
||||||
pub to: Path,
|
|
||||||
pub init: Vec<Fielder>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [Struct field initializer] expression: [Sym] (`=` [Expr])?
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Fielder {
|
|
||||||
pub name: Sym,
|
|
||||||
pub init: Option<Box<Expr>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]`
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Array {
|
|
||||||
pub values: Vec<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An Array literal constructed with [repeat syntax](ArrayRep)
|
|
||||||
/// `[` [Expr] `;` [Literal] `]`
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct ArrayRep {
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
pub repeat: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An address-of expression: `&` `mut`? [`Expr`]
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct AddrOf {
|
|
||||||
pub mutable: Mutability,
|
|
||||||
pub expr: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A cast expression: [`Expr`] `as` [`Ty`]
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Cast {
|
|
||||||
pub head: Box<Expr>,
|
|
||||||
pub ty: Ty,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A backtick-quoted subexpression-literal
|
/// A backtick-quoted subexpression-literal
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Quote {
|
pub struct Quote {
|
||||||
pub quote: Box<Expr>,
|
pub quote: Box<ExprKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Literal]: 0x42, 1e123, 2.4, "Hello"
|
/// A local variable declaration [Stmt]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Literal {
|
pub struct Let {
|
||||||
Bool(bool),
|
pub mutable: Mutability,
|
||||||
Char(char),
|
pub name: Pattern,
|
||||||
Int(u128),
|
pub ty: Option<Box<Ty>>,
|
||||||
Float(u64),
|
pub init: Option<Box<Expr>>,
|
||||||
String(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Grouping](Group) expression `(` [`Expr`] `)`
|
/// A [Pattern] meta-expression (any [`ExprKind`] that fits pattern rules)
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Group {
|
pub enum Pattern {
|
||||||
pub expr: Box<Expr>,
|
Path(Path),
|
||||||
|
Literal(Literal),
|
||||||
|
Ref(Mutability, Box<Pattern>),
|
||||||
|
Tuple(Vec<Pattern>),
|
||||||
|
Array(Vec<Pattern>),
|
||||||
|
Struct(Path, Vec<(Path, Option<Pattern>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Block] expression: `{` [`Stmt`]\* [`Expr`]? `}`
|
/// A `match` expression: `match` `{` ([MatchArm] `,`)* [MatchArm]? `}`
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Block {
|
pub struct Match {
|
||||||
pub stmts: Vec<Stmt>,
|
pub scrutinee: Box<Expr>,
|
||||||
|
pub arms: Vec<MatchArm>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single arm of a [Match] expression: [`Pattern`] `=>` [`Expr`]
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct MatchArm(pub Pattern, pub Expr);
|
||||||
|
|
||||||
/// An [Assign]ment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
/// An [Assign]ment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Assign {
|
pub struct Assign {
|
||||||
pub parts: Box<(Expr, Expr)>,
|
pub parts: Box<(ExprKind, ExprKind)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Modify {
|
pub struct Modify {
|
||||||
pub kind: ModifyKind,
|
pub kind: ModifyKind,
|
||||||
pub parts: Box<(Expr, Expr)>,
|
pub parts: Box<(ExprKind, ExprKind)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
@ -487,7 +468,7 @@ pub enum ModifyKind {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Binary {
|
pub struct Binary {
|
||||||
pub kind: BinaryKind,
|
pub kind: BinaryKind,
|
||||||
pub parts: Box<(Expr, Expr)>,
|
pub parts: Box<(ExprKind, ExprKind)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Binary] operator
|
/// A [Binary] operator
|
||||||
@ -521,7 +502,7 @@ pub enum BinaryKind {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Unary {
|
pub struct Unary {
|
||||||
pub kind: UnaryKind,
|
pub kind: UnaryKind,
|
||||||
pub tail: Box<Expr>,
|
pub tail: Box<ExprKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Unary] operator
|
/// A [Unary] operator
|
||||||
@ -530,8 +511,6 @@ pub enum UnaryKind {
|
|||||||
Deref,
|
Deref,
|
||||||
Neg,
|
Neg,
|
||||||
Not,
|
Not,
|
||||||
RangeInc,
|
|
||||||
RangeExc,
|
|
||||||
/// A Loop expression: `loop` [`Block`]
|
/// A Loop expression: `loop` [`Block`]
|
||||||
Loop,
|
Loop,
|
||||||
/// Unused
|
/// Unused
|
||||||
@ -540,10 +519,17 @@ pub enum UnaryKind {
|
|||||||
Tilde,
|
Tilde,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A cast expression: [`Expr`] `as` [`Ty`]
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Cast {
|
||||||
|
pub head: Box<ExprKind>,
|
||||||
|
pub ty: Ty,
|
||||||
|
}
|
||||||
|
|
||||||
/// A [Member] access expression: [`Expr`] [`MemberKind`]\*
|
/// A [Member] access expression: [`Expr`] [`MemberKind`]\*
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Member {
|
pub struct Member {
|
||||||
pub head: Box<Expr>,
|
pub head: Box<ExprKind>,
|
||||||
pub kind: MemberKind,
|
pub kind: MemberKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,44 +544,61 @@ pub enum MemberKind {
|
|||||||
/// A repeated [Index] expression: a[10, 20, 30][40, 50, 60]
|
/// A repeated [Index] expression: a[10, 20, 30][40, 50, 60]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Index {
|
pub struct Index {
|
||||||
pub head: Box<Expr>,
|
pub head: Box<ExprKind>,
|
||||||
pub indices: Vec<Expr>,
|
pub indices: Vec<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A local variable declaration [Stmt]
|
/// A [Struct creation](Structor) expression: [Path] `{` ([Fielder] `,`)* [Fielder]? `}`
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Let {
|
pub struct Structor {
|
||||||
pub mutable: Mutability,
|
pub to: Path,
|
||||||
pub name: Pattern,
|
pub init: Vec<Fielder>,
|
||||||
pub ty: Option<Box<Ty>>,
|
}
|
||||||
|
|
||||||
|
/// A [Struct field initializer] expression: [Sym] (`=` [Expr])?
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Fielder {
|
||||||
|
pub name: Sym,
|
||||||
pub init: Option<Box<Expr>>,
|
pub init: Option<Box<Expr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `match` expression: `match` `{` ([MatchArm] `,`)* [MatchArm]? `}`
|
/// An [Array] literal: `[` [`Expr`] (`,` [`Expr`])\* `]`
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Match {
|
pub struct Array {
|
||||||
pub scrutinee: Box<Expr>,
|
pub values: Vec<Expr>,
|
||||||
pub arms: Vec<MatchArm>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single arm of a [Match] expression: [`Pattern`] `=>` [`Expr`]
|
/// An Array literal constructed with [repeat syntax](ArrayRep)
|
||||||
|
/// `[` [Expr] `;` [Literal] `]`
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct MatchArm(pub Pattern, pub Expr);
|
pub struct ArrayRep {
|
||||||
|
pub value: Box<ExprKind>,
|
||||||
|
pub repeat: Box<ExprKind>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A [Pattern] meta-expression (any [`ExprKind`] that fits pattern rules)
|
/// An address-of expression: `&` `mut`? [`Expr`]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Pattern {
|
pub struct AddrOf {
|
||||||
Name(Sym),
|
pub mutable: Mutability,
|
||||||
Path(Path),
|
pub expr: Box<ExprKind>,
|
||||||
Literal(Literal),
|
}
|
||||||
Rest(Option<Box<Pattern>>),
|
|
||||||
Ref(Mutability, Box<Pattern>),
|
/// A [Block] expression: `{` [`Stmt`]\* [`Expr`]? `}`
|
||||||
RangeExc(Box<Pattern>, Box<Pattern>),
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
RangeInc(Box<Pattern>, Box<Pattern>),
|
pub struct Block {
|
||||||
Tuple(Vec<Pattern>),
|
pub stmts: Vec<Stmt>,
|
||||||
Array(Vec<Pattern>),
|
}
|
||||||
Struct(Path, Vec<(Sym, Option<Pattern>)>),
|
|
||||||
TupleStruct(Path, Vec<Pattern>),
|
/// A [Grouping](Group) expression `(` [`Expr`] `)`
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Group {
|
||||||
|
pub expr: Box<ExprKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Tuple {
|
||||||
|
pub exprs: Vec<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
|
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
|
||||||
@ -617,7 +620,7 @@ pub struct If {
|
|||||||
/// A [For] expression: `for` Pattern `in` [`Expr`] [`Block`] [`Else`]?
|
/// A [For] expression: `for` Pattern `in` [`Expr`] [`Block`] [`Else`]?
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct For {
|
pub struct For {
|
||||||
pub bind: Pattern,
|
pub bind: Sym, // TODO: Patterns?
|
||||||
pub cond: Box<Expr>,
|
pub cond: Box<Expr>,
|
||||||
pub pass: Box<Block>,
|
pub pass: Box<Block>,
|
||||||
pub fail: Else,
|
pub fail: Else,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,161 +0,0 @@
|
|||||||
//! Converts between major enums and enum variants
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl<T: AsRef<str>> From<T> for PathPart {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
match value.as_ref() {
|
|
||||||
"super" => PathPart::SuperKw,
|
|
||||||
ident => PathPart::Ident(ident.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro impl_from ($(impl From for $T:ty {$($from:ty => $to:expr),*$(,)?})*) {$($(
|
|
||||||
impl From<$from> for $T {
|
|
||||||
fn from(value: $from) -> Self {
|
|
||||||
$to(value.into()) // Uses *tuple constructor*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Box<$from>> for $T {
|
|
||||||
fn from(value: Box<$from>) -> Self {
|
|
||||||
$to((*value).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*)*}
|
|
||||||
|
|
||||||
impl_from! {
|
|
||||||
impl From for ItemKind {
|
|
||||||
Alias => ItemKind::Alias,
|
|
||||||
Const => ItemKind::Const,
|
|
||||||
Static => ItemKind::Static,
|
|
||||||
Module => ItemKind::Module,
|
|
||||||
Function => ItemKind::Function,
|
|
||||||
Struct => ItemKind::Struct,
|
|
||||||
Enum => ItemKind::Enum,
|
|
||||||
Impl => ItemKind::Impl,
|
|
||||||
Use => ItemKind::Use,
|
|
||||||
}
|
|
||||||
impl From for StructKind {
|
|
||||||
Vec<Ty> => StructKind::Tuple,
|
|
||||||
// TODO: Struct members in struct
|
|
||||||
}
|
|
||||||
impl From for TyKind {
|
|
||||||
Path => TyKind::Path,
|
|
||||||
TyTuple => TyKind::Tuple,
|
|
||||||
TyRef => TyKind::Ref,
|
|
||||||
TyFn => TyKind::Fn,
|
|
||||||
}
|
|
||||||
impl From for StmtKind {
|
|
||||||
Item => StmtKind::Item,
|
|
||||||
Expr => StmtKind::Expr,
|
|
||||||
}
|
|
||||||
impl From for ExprKind {
|
|
||||||
Let => ExprKind::Let,
|
|
||||||
Closure => ExprKind::Closure,
|
|
||||||
Quote => ExprKind::Quote,
|
|
||||||
Match => ExprKind::Match,
|
|
||||||
Assign => ExprKind::Assign,
|
|
||||||
Modify => ExprKind::Modify,
|
|
||||||
Binary => ExprKind::Binary,
|
|
||||||
Unary => ExprKind::Unary,
|
|
||||||
Cast => ExprKind::Cast,
|
|
||||||
Member => ExprKind::Member,
|
|
||||||
Index => ExprKind::Index,
|
|
||||||
Path => ExprKind::Path,
|
|
||||||
Literal => ExprKind::Literal,
|
|
||||||
Array => ExprKind::Array,
|
|
||||||
ArrayRep => ExprKind::ArrayRep,
|
|
||||||
AddrOf => ExprKind::AddrOf,
|
|
||||||
Block => ExprKind::Block,
|
|
||||||
Group => ExprKind::Group,
|
|
||||||
Tuple => ExprKind::Tuple,
|
|
||||||
While => ExprKind::While,
|
|
||||||
If => ExprKind::If,
|
|
||||||
For => ExprKind::For,
|
|
||||||
Break => ExprKind::Break,
|
|
||||||
Return => ExprKind::Return,
|
|
||||||
}
|
|
||||||
impl From for Literal {
|
|
||||||
bool => Literal::Bool,
|
|
||||||
char => Literal::Char,
|
|
||||||
u128 => Literal::Int,
|
|
||||||
String => Literal::String,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Option<Expr>> for Else {
|
|
||||||
fn from(value: Option<Expr>) -> Self {
|
|
||||||
Self { body: value.map(Into::into) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<Expr> for Else {
|
|
||||||
fn from(value: Expr) -> Self {
|
|
||||||
Self { body: Some(value.into()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Expr> for Pattern {
|
|
||||||
type Error = Expr;
|
|
||||||
|
|
||||||
/// Performs the conversion. On failure, returns the *first* non-pattern subexpression.
|
|
||||||
fn try_from(value: Expr) -> Result<Self, Self::Error> {
|
|
||||||
Ok(match value.kind {
|
|
||||||
ExprKind::Literal(literal) => Pattern::Literal(literal),
|
|
||||||
ExprKind::Path(Path { absolute: false, ref parts }) => match parts.as_slice() {
|
|
||||||
[PathPart::Ident(name)] => Pattern::Name(*name),
|
|
||||||
_ => Err(value)?,
|
|
||||||
},
|
|
||||||
ExprKind::Empty => Pattern::Tuple(vec![]),
|
|
||||||
ExprKind::Group(Group { expr }) => Pattern::Tuple(vec![Pattern::try_from(*expr)?]),
|
|
||||||
ExprKind::Tuple(Tuple { exprs }) => Pattern::Tuple(
|
|
||||||
exprs
|
|
||||||
.into_iter()
|
|
||||||
.map(Pattern::try_from)
|
|
||||||
.collect::<Result<_, _>>()?,
|
|
||||||
),
|
|
||||||
ExprKind::AddrOf(AddrOf { mutable, expr }) => {
|
|
||||||
Pattern::Ref(mutable, Box::new(Pattern::try_from(*expr)?))
|
|
||||||
}
|
|
||||||
ExprKind::Array(Array { values }) => Pattern::Array(
|
|
||||||
values
|
|
||||||
.into_iter()
|
|
||||||
.map(Pattern::try_from)
|
|
||||||
.collect::<Result<_, _>>()?,
|
|
||||||
),
|
|
||||||
ExprKind::Binary(Binary { kind: BinaryKind::Call, parts }) => {
|
|
||||||
let (Expr { kind: ExprKind::Path(path), .. }, args) = *parts else {
|
|
||||||
return Err(parts.0);
|
|
||||||
};
|
|
||||||
match args.kind {
|
|
||||||
ExprKind::Empty | ExprKind::Tuple(_) => {}
|
|
||||||
_ => return Err(args),
|
|
||||||
}
|
|
||||||
let Pattern::Tuple(args) = Pattern::try_from(args)? else {
|
|
||||||
unreachable!("Arguments should be convertible to pattern!")
|
|
||||||
};
|
|
||||||
Pattern::TupleStruct(path, args)
|
|
||||||
}
|
|
||||||
ExprKind::Binary(Binary { kind: BinaryKind::RangeExc, parts }) => {
|
|
||||||
let (head, tail) = (Pattern::try_from(parts.0)?, Pattern::try_from(parts.1)?);
|
|
||||||
Pattern::RangeExc(head.into(), tail.into())
|
|
||||||
}
|
|
||||||
ExprKind::Binary(Binary { kind: BinaryKind::RangeInc, parts }) => {
|
|
||||||
let (head, tail) = (Pattern::try_from(parts.0)?, Pattern::try_from(parts.1)?);
|
|
||||||
Pattern::RangeInc(head.into(), tail.into())
|
|
||||||
}
|
|
||||||
ExprKind::Unary(Unary { kind: UnaryKind::RangeExc, tail }) => {
|
|
||||||
Pattern::Rest(Some(Pattern::try_from(*tail)?.into()))
|
|
||||||
}
|
|
||||||
ExprKind::Structor(Structor { to, init }) => {
|
|
||||||
let fields = init
|
|
||||||
.into_iter()
|
|
||||||
.map(|Fielder { name, init }| {
|
|
||||||
Ok((name, init.map(|i| Pattern::try_from(*i)).transpose()?))
|
|
||||||
})
|
|
||||||
.collect::<Result<_, Self::Error>>()?;
|
|
||||||
Pattern::Struct(to, fields)
|
|
||||||
}
|
|
||||||
_ => Err(value)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,761 +0,0 @@
|
|||||||
//! Implements [Display] for [AST](super::super) Types
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use format::{delimiters::*, *};
|
|
||||||
use std::{
|
|
||||||
borrow::Borrow,
|
|
||||||
fmt::{Display, Write},
|
|
||||||
};
|
|
||||||
|
|
||||||
fn separate<I: Display, W: Write>(
|
|
||||||
iterable: impl IntoIterator<Item = I>,
|
|
||||||
sep: &'static str,
|
|
||||||
) -> impl FnOnce(W) -> std::fmt::Result {
|
|
||||||
move |mut f| {
|
|
||||||
for (idx, item) in iterable.into_iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
f.write_str(sep)?;
|
|
||||||
}
|
|
||||||
write!(f, "{item}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Mutability {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Mutability::Not => Ok(()),
|
|
||||||
Mutability::Mut => "mut ".fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Visibility {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Visibility::Private => Ok(()),
|
|
||||||
Visibility::Public => "pub ".fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Literal {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Literal::Bool(v) => v.fmt(f),
|
|
||||||
Literal::Char(v) => write!(f, "'{}'", v.escape_debug()),
|
|
||||||
Literal::Int(v) => v.fmt(f),
|
|
||||||
Literal::Float(v) => write!(f, "{:?}", f64::from_bits(*v)),
|
|
||||||
Literal::String(v) => write!(f, "\"{}\"", v.escape_debug()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for File {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
separate(&self.items, "\n\n")(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Attrs {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { meta } = self;
|
|
||||||
if meta.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
"#".fmt(f)?;
|
|
||||||
separate(meta, ", ")(&mut f.delimit(INLINE_SQUARE))?;
|
|
||||||
"\n".fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Meta {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, kind } = self;
|
|
||||||
write!(f, "{name}{kind}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for MetaKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
MetaKind::Plain => Ok(()),
|
|
||||||
MetaKind::Equals(v) => write!(f, " = {v}"),
|
|
||||||
MetaKind::Func(args) => separate(args, ", ")(f.delimit(INLINE_PARENS)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Item {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { span: _, attrs, vis, kind } = self;
|
|
||||||
attrs.fmt(f)?;
|
|
||||||
vis.fmt(f)?;
|
|
||||||
kind.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ItemKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
ItemKind::Alias(v) => v.fmt(f),
|
|
||||||
ItemKind::Const(v) => v.fmt(f),
|
|
||||||
ItemKind::Static(v) => v.fmt(f),
|
|
||||||
ItemKind::Module(v) => v.fmt(f),
|
|
||||||
ItemKind::Function(v) => v.fmt(f),
|
|
||||||
ItemKind::Struct(v) => v.fmt(f),
|
|
||||||
ItemKind::Enum(v) => v.fmt(f),
|
|
||||||
ItemKind::Impl(v) => v.fmt(f),
|
|
||||||
ItemKind::Use(v) => v.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Generics {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Generics { vars } = self;
|
|
||||||
if !vars.is_empty() {
|
|
||||||
separate(vars, ", ")(f.delimit_with("<", ">"))?
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Alias {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, from } = self;
|
|
||||||
match from {
|
|
||||||
Some(from) => write!(f, "type {name} = {from};"),
|
|
||||||
None => write!(f, "type {name};"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Const {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, ty, init } = self;
|
|
||||||
write!(f, "const {name}: {ty} = {init}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Static {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { mutable, name, ty, init } = self;
|
|
||||||
write!(f, "static {mutable}{name}: {ty} = {init}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Module {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, file } = self;
|
|
||||||
write!(f, "mod {name}")?;
|
|
||||||
match file {
|
|
||||||
Some(items) => {
|
|
||||||
' '.fmt(f)?;
|
|
||||||
write!(f.delimit(BRACES), "{items}")
|
|
||||||
}
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Function {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, gens, sign: sign @ TyFn { args, rety }, bind, body } = self;
|
|
||||||
let types = match **args {
|
|
||||||
TyKind::Tuple(TyTuple { ref types }) => types.as_slice(),
|
|
||||||
TyKind::Empty => Default::default(),
|
|
||||||
_ => {
|
|
||||||
write!(f, "Invalid function signature: {sign}")?;
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let bind = match bind {
|
|
||||||
Pattern::Tuple(patterns) => patterns.as_slice(),
|
|
||||||
_ => {
|
|
||||||
write!(f, "Invalid argument binder: {bind}")?;
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
debug_assert_eq!(bind.len(), types.len());
|
|
||||||
write!(f, "fn {name}{gens} ")?;
|
|
||||||
{
|
|
||||||
let mut f = f.delimit(INLINE_PARENS);
|
|
||||||
|
|
||||||
for (idx, (arg, ty)) in bind.iter().zip(types.iter()).enumerate() {
|
|
||||||
if idx != 0 {
|
|
||||||
f.write_str(", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{arg}: {ty}")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(rety) = rety {
|
|
||||||
write!(f, " -> {rety}")?;
|
|
||||||
}
|
|
||||||
match body {
|
|
||||||
Some(body) => write!(f, " {body}"),
|
|
||||||
None => ';'.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Struct {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, gens, kind } = self;
|
|
||||||
write!(f, "struct {name}{gens}{kind}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for StructKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
StructKind::Empty => ';'.fmt(f),
|
|
||||||
StructKind::Tuple(v) => separate(v, ", ")(f.delimit(INLINE_PARENS)),
|
|
||||||
StructKind::Struct(v) => separate(v, ",\n")(f.delimit(SPACED_BRACES)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for StructMember {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { vis, name, ty } = self;
|
|
||||||
write!(f, "{vis}{name}: {ty}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Enum {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, gens, variants } = self;
|
|
||||||
write!(f, "enum {name}{gens}")?;
|
|
||||||
separate(variants, ",\n")(f.delimit(SPACED_BRACES))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Variant {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, kind, body } = self;
|
|
||||||
write!(f, "{name}{kind}")?;
|
|
||||||
match body {
|
|
||||||
Some(body) => write!(f, " {body}"),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Impl {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { target, body } = self;
|
|
||||||
write!(f, "impl {target} ")?;
|
|
||||||
write!(f.delimit(BRACES), "{body}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ImplKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
ImplKind::Type(t) => t.fmt(f),
|
|
||||||
ImplKind::Trait { impl_trait, for_type } => {
|
|
||||||
write!(f, "{impl_trait} for {for_type}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Use {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { absolute, tree } = self;
|
|
||||||
f.write_str(if *absolute { "use ::" } else { "use " })?;
|
|
||||||
write!(f, "{tree};")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for UseTree {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
UseTree::Tree(tree) => separate(tree, ", ")(f.delimit(INLINE_BRACES)),
|
|
||||||
UseTree::Path(path, rest) => write!(f, "{path}::{rest}"),
|
|
||||||
UseTree::Alias(path, name) => write!(f, "{path} as {name}"),
|
|
||||||
UseTree::Name(name) => write!(f, "{name}"),
|
|
||||||
UseTree::Glob => write!(f, "*"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Ty {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.kind.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TyKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
TyKind::Never => "!".fmt(f),
|
|
||||||
TyKind::Empty => "()".fmt(f),
|
|
||||||
TyKind::Infer => "_".fmt(f),
|
|
||||||
TyKind::Path(v) => v.fmt(f),
|
|
||||||
TyKind::Array(v) => v.fmt(f),
|
|
||||||
TyKind::Slice(v) => v.fmt(f),
|
|
||||||
TyKind::Tuple(v) => v.fmt(f),
|
|
||||||
TyKind::Ref(v) => v.fmt(f),
|
|
||||||
TyKind::Fn(v) => v.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TyArray {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { ty, count } = self;
|
|
||||||
write!(f, "[{ty}; {count}]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TySlice {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { ty } = self;
|
|
||||||
write!(f, "[{ty}]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TyTuple {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
separate(&self.types, ", ")(f.delimit(INLINE_PARENS))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TyRef {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let &Self { count, mutable, ref to } = self;
|
|
||||||
for _ in 0..count {
|
|
||||||
f.write_char('&')?;
|
|
||||||
}
|
|
||||||
write!(f, "{mutable}{to}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TyFn {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { args, rety } = self;
|
|
||||||
write!(f, "fn {args}")?;
|
|
||||||
match rety {
|
|
||||||
Some(v) => write!(f, " -> {v}"),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Path {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { absolute, parts } = self;
|
|
||||||
if *absolute {
|
|
||||||
"::".fmt(f)?;
|
|
||||||
}
|
|
||||||
separate(parts, "::")(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for PathPart {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
PathPart::SuperKw => "super".fmt(f),
|
|
||||||
PathPart::SelfTy => "Self".fmt(f),
|
|
||||||
PathPart::Ident(id) => id.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Stmt {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Stmt { span: _, kind, semi } = self;
|
|
||||||
write!(f, "{kind}{semi}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for StmtKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
StmtKind::Empty => Ok(()),
|
|
||||||
StmtKind::Item(v) => v.fmt(f),
|
|
||||||
StmtKind::Expr(v) => v.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Semi {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Semi::Terminated => ';'.fmt(f),
|
|
||||||
Semi::Unterminated => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Expr {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.kind.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ExprKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
ExprKind::Empty => "()".fmt(f),
|
|
||||||
ExprKind::Closure(v) => v.fmt(f),
|
|
||||||
ExprKind::Quote(v) => v.fmt(f),
|
|
||||||
ExprKind::Let(v) => v.fmt(f),
|
|
||||||
ExprKind::Match(v) => v.fmt(f),
|
|
||||||
ExprKind::Assign(v) => v.fmt(f),
|
|
||||||
ExprKind::Modify(v) => v.fmt(f),
|
|
||||||
ExprKind::Binary(v) => v.fmt(f),
|
|
||||||
ExprKind::Unary(v) => v.fmt(f),
|
|
||||||
ExprKind::Cast(v) => v.fmt(f),
|
|
||||||
ExprKind::Member(v) => v.fmt(f),
|
|
||||||
ExprKind::Index(v) => v.fmt(f),
|
|
||||||
ExprKind::Structor(v) => v.fmt(f),
|
|
||||||
ExprKind::Path(v) => v.fmt(f),
|
|
||||||
ExprKind::Literal(v) => v.fmt(f),
|
|
||||||
ExprKind::Array(v) => v.fmt(f),
|
|
||||||
ExprKind::ArrayRep(v) => v.fmt(f),
|
|
||||||
ExprKind::AddrOf(v) => v.fmt(f),
|
|
||||||
ExprKind::Block(v) => v.fmt(f),
|
|
||||||
ExprKind::Group(v) => v.fmt(f),
|
|
||||||
ExprKind::Tuple(v) => v.fmt(f),
|
|
||||||
ExprKind::While(v) => v.fmt(f),
|
|
||||||
ExprKind::If(v) => v.fmt(f),
|
|
||||||
ExprKind::For(v) => v.fmt(f),
|
|
||||||
ExprKind::Break(v) => v.fmt(f),
|
|
||||||
ExprKind::Return(v) => v.fmt(f),
|
|
||||||
ExprKind::Continue => "continue".fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Closure {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { arg, body } = self;
|
|
||||||
match arg.as_ref() {
|
|
||||||
Pattern::Tuple(args) => separate(args, ", ")(f.delimit_with("|", "|")),
|
|
||||||
_ => arg.fmt(f),
|
|
||||||
}?;
|
|
||||||
write!(f, " {body}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Quote {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { quote } = self;
|
|
||||||
write!(f, "`{quote}`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Let {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { mutable, name, ty, init } = self;
|
|
||||||
write!(f, "let {mutable}{name}")?;
|
|
||||||
if let Some(value) = ty {
|
|
||||||
write!(f, ": {value}")?;
|
|
||||||
}
|
|
||||||
if let Some(value) = init {
|
|
||||||
write!(f, " = {value}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Pattern {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Pattern::Name(sym) => sym.fmt(f),
|
|
||||||
Pattern::Path(path) => path.fmt(f),
|
|
||||||
Pattern::Literal(literal) => literal.fmt(f),
|
|
||||||
Pattern::Rest(Some(name)) => write!(f, "..{name}"),
|
|
||||||
Pattern::Rest(None) => "..".fmt(f),
|
|
||||||
Pattern::Ref(mutability, pattern) => write!(f, "&{mutability}{pattern}"),
|
|
||||||
Pattern::RangeExc(head, tail) => write!(f, "{head}..{tail}"),
|
|
||||||
Pattern::RangeInc(head, tail) => write!(f, "{head}..={tail}"),
|
|
||||||
Pattern::Tuple(patterns) => separate(patterns, ", ")(f.delimit(INLINE_PARENS)),
|
|
||||||
Pattern::Array(patterns) => separate(patterns, ", ")(f.delimit(INLINE_SQUARE)),
|
|
||||||
Pattern::Struct(path, items) => {
|
|
||||||
write!(f, "{path} ")?;
|
|
||||||
let f = &mut f.delimit(INLINE_BRACES);
|
|
||||||
for (idx, (name, item)) in items.iter().enumerate() {
|
|
||||||
if idx != 0 {
|
|
||||||
f.write_str(", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{name}")?;
|
|
||||||
if let Some(pattern) = item {
|
|
||||||
write!(f, ": {pattern}")?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Pattern::TupleStruct(path, items) => {
|
|
||||||
write!(f, "{path}")?;
|
|
||||||
separate(items, ", ")(f.delimit(INLINE_PARENS))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Match {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { scrutinee, arms } = self;
|
|
||||||
write!(f, "match {scrutinee} ")?;
|
|
||||||
separate(arms, ",\n")(f.delimit(BRACES))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for MatchArm {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self(pat, expr) = self;
|
|
||||||
write!(f, "{pat} => {expr}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Assign {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { parts } = self;
|
|
||||||
write!(f, "{} = {}", parts.0, parts.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Modify {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { kind, parts } = self;
|
|
||||||
write!(f, "{} {kind} {}", parts.0, parts.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ModifyKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
ModifyKind::Mul => "*=",
|
|
||||||
ModifyKind::Div => "/=",
|
|
||||||
ModifyKind::Rem => "%=",
|
|
||||||
ModifyKind::Add => "+=",
|
|
||||||
ModifyKind::Sub => "-=",
|
|
||||||
ModifyKind::And => "&=",
|
|
||||||
ModifyKind::Or => "|=",
|
|
||||||
ModifyKind::Xor => "^=",
|
|
||||||
ModifyKind::Shl => "<<=",
|
|
||||||
ModifyKind::Shr => ">>=",
|
|
||||||
}
|
|
||||||
.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Binary {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { kind, parts } = self;
|
|
||||||
let (head, tail) = parts.borrow();
|
|
||||||
match kind {
|
|
||||||
BinaryKind::Call => write!(f, "{head}{tail}"),
|
|
||||||
_ => write!(f, "{head} {kind} {tail}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for BinaryKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
BinaryKind::Lt => "<",
|
|
||||||
BinaryKind::LtEq => "<=",
|
|
||||||
BinaryKind::Equal => "==",
|
|
||||||
BinaryKind::NotEq => "!=",
|
|
||||||
BinaryKind::GtEq => ">=",
|
|
||||||
BinaryKind::Gt => ">",
|
|
||||||
BinaryKind::RangeExc => "..",
|
|
||||||
BinaryKind::RangeInc => "..=",
|
|
||||||
BinaryKind::LogAnd => "&&",
|
|
||||||
BinaryKind::LogOr => "||",
|
|
||||||
BinaryKind::LogXor => "^^",
|
|
||||||
BinaryKind::BitAnd => "&",
|
|
||||||
BinaryKind::BitOr => "|",
|
|
||||||
BinaryKind::BitXor => "^",
|
|
||||||
BinaryKind::Shl => "<<",
|
|
||||||
BinaryKind::Shr => ">>",
|
|
||||||
BinaryKind::Add => "+",
|
|
||||||
BinaryKind::Sub => "-",
|
|
||||||
BinaryKind::Mul => "*",
|
|
||||||
BinaryKind::Div => "/",
|
|
||||||
BinaryKind::Rem => "%",
|
|
||||||
BinaryKind::Call => "()",
|
|
||||||
}
|
|
||||||
.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Unary {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { kind, tail } = self;
|
|
||||||
write!(f, "{kind}{tail}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for UnaryKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
UnaryKind::Loop => "loop ",
|
|
||||||
UnaryKind::Deref => "*",
|
|
||||||
UnaryKind::Neg => "-",
|
|
||||||
UnaryKind::Not => "!",
|
|
||||||
UnaryKind::RangeExc => "..",
|
|
||||||
UnaryKind::RangeInc => "..=",
|
|
||||||
UnaryKind::At => "@",
|
|
||||||
UnaryKind::Tilde => "~",
|
|
||||||
}
|
|
||||||
.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Cast {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { head, ty } = self;
|
|
||||||
write!(f, "{head} as {ty}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Member {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { head, kind } = self;
|
|
||||||
write!(f, "{head}.{kind}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for MemberKind {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
MemberKind::Call(name, args) => write!(f, "{name}{args}"),
|
|
||||||
MemberKind::Struct(name) => write!(f, "{name}"),
|
|
||||||
MemberKind::Tuple(name) => write!(f, "{name}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Index {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { head, indices } = self;
|
|
||||||
write!(f, "{head}")?;
|
|
||||||
separate(indices, ", ")(f.delimit(INLINE_SQUARE))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Structor {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { to, init } = self;
|
|
||||||
write!(f, "{to} ")?;
|
|
||||||
separate(init, ", ")(f.delimit(INLINE_BRACES))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Fielder {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { name, init } = self;
|
|
||||||
write!(f, "{name}")?;
|
|
||||||
if let Some(init) = init {
|
|
||||||
write!(f, ": {init}")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Array {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
separate(&self.values, ", ")(f.delimit(INLINE_SQUARE))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ArrayRep {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { value, repeat } = self;
|
|
||||||
write!(f, "[{value}; {repeat}]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for AddrOf {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { mutable, expr } = self;
|
|
||||||
write!(f, "&{mutable}{expr}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Block {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { stmts } = self;
|
|
||||||
|
|
||||||
match stmts.as_slice() {
|
|
||||||
[] => "{}".fmt(f),
|
|
||||||
stmts => separate(stmts, "\n")(f.delimit(BRACES)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Group {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "({})", self.expr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Tuple {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { exprs } = self;
|
|
||||||
|
|
||||||
match exprs.as_slice() {
|
|
||||||
[] => write!(f, "()"),
|
|
||||||
[expr] => write!(f, "({expr},)"),
|
|
||||||
exprs => separate(exprs, ", ")(f.delimit(INLINE_PARENS)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for While {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { cond, pass, fail } = self;
|
|
||||||
write!(f, "while {cond} {pass}{fail}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for If {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { cond, pass, fail } = self;
|
|
||||||
write!(f, "if {cond} {pass}{fail}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for For {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { bind, cond, pass, fail } = self;
|
|
||||||
write!(f, "for {bind} in {cond} {pass}{fail}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Else {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match &self.body {
|
|
||||||
Some(body) => write!(f, " else {body}"),
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Break {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "break")?;
|
|
||||||
match &self.body {
|
|
||||||
Some(body) => write!(f, " {body}"),
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Return {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "return")?;
|
|
||||||
match &self.body {
|
|
||||||
Some(body) => write!(f, " {body}"),
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
//! Utils for [Path]
|
|
||||||
use crate::{PathPart, Sym, ast::Path};
|
|
||||||
|
|
||||||
impl Path {
|
|
||||||
/// Appends a [PathPart] to this [Path]
|
|
||||||
pub fn push(&mut self, part: PathPart) {
|
|
||||||
self.parts.push(part);
|
|
||||||
}
|
|
||||||
/// Removes a [PathPart] from this [Path]
|
|
||||||
pub fn pop(&mut self) -> Option<PathPart> {
|
|
||||||
self.parts.pop()
|
|
||||||
}
|
|
||||||
/// Concatenates `self::other`. If `other` is an absolute [Path],
|
|
||||||
/// this replaces `self` with `other`
|
|
||||||
pub fn concat(mut self, other: &Self) -> Self {
|
|
||||||
if other.absolute {
|
|
||||||
other.clone()
|
|
||||||
} else {
|
|
||||||
self.parts.extend(other.parts.iter().cloned());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the defining [Sym] of this path
|
|
||||||
pub fn as_sym(&self) -> Option<Sym> {
|
|
||||||
match self.parts.as_slice() {
|
|
||||||
[.., PathPart::Ident(name)] => Some(*name),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether this path ends in the given [Sym]
|
|
||||||
pub fn ends_with(&self, name: &str) -> bool {
|
|
||||||
match self.parts.as_slice() {
|
|
||||||
[.., PathPart::Ident(last)] => name == &**last,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether this path refers to the sinkhole identifier, `_`
|
|
||||||
pub fn is_sinkhole(&self) -> bool {
|
|
||||||
if let [PathPart::Ident(id)] = self.parts.as_slice() {
|
|
||||||
if let "_" = id.to_ref() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl PathPart {
|
|
||||||
pub fn from_sym(ident: Sym) -> Self {
|
|
||||||
Self::Ident(ident)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Sym> for Path {
|
|
||||||
fn from(value: Sym) -> Self {
|
|
||||||
Self { parts: vec![PathPart::Ident(value)], absolute: false }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,609 +0,0 @@
|
|||||||
//! Approximates the size of an AST
|
|
||||||
|
|
||||||
use std::mem::size_of_val;
|
|
||||||
|
|
||||||
use crate::ast::*;
|
|
||||||
use cl_structures::{intern::interned::Interned, span::Span};
|
|
||||||
|
|
||||||
/// Approximates the size of an AST without including indirection (pointers) or padding
|
|
||||||
pub trait WeightOf {
|
|
||||||
/// Approximates the size of a syntax tree without including pointer/indirection or padding.
|
|
||||||
fn weight_of(&self) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for File {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, items } = self;
|
|
||||||
name.weight_of() + items.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Attrs {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { meta } = self;
|
|
||||||
meta.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Meta {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, kind } = self;
|
|
||||||
name.weight_of() + kind.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for MetaKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
MetaKind::Plain => size_of_val(self),
|
|
||||||
MetaKind::Equals(v) => v.weight_of(),
|
|
||||||
MetaKind::Func(v) => v.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Item {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { span, attrs, vis, kind } = self;
|
|
||||||
span.weight_of() + attrs.weight_of() + vis.weight_of() + kind.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for ItemKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
ItemKind::Module(v) => v.weight_of(),
|
|
||||||
ItemKind::Alias(v) => v.weight_of(),
|
|
||||||
ItemKind::Enum(v) => v.weight_of(),
|
|
||||||
ItemKind::Struct(v) => v.weight_of(),
|
|
||||||
ItemKind::Const(v) => v.weight_of(),
|
|
||||||
ItemKind::Static(v) => v.weight_of(),
|
|
||||||
ItemKind::Function(v) => v.weight_of(),
|
|
||||||
ItemKind::Impl(v) => v.weight_of(),
|
|
||||||
ItemKind::Use(v) => v.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Generics {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { vars } = self;
|
|
||||||
vars.iter().map(|v| v.weight_of()).sum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Module {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, file } = self;
|
|
||||||
name.weight_of() + file.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Alias {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, from } = self;
|
|
||||||
name.weight_of() + from.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Const {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, ty, init } = self;
|
|
||||||
name.weight_of() + ty.weight_of() + init.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Static {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { mutable, name, ty, init } = self;
|
|
||||||
mutable.weight_of() + name.weight_of() + ty.weight_of() + init.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Function {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, gens, sign, bind, body } = self;
|
|
||||||
name.weight_of() + gens.weight_of() + sign.weight_of() + bind.weight_of() + body.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Struct {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, gens, kind } = self;
|
|
||||||
name.weight_of() + gens.weight_of() + kind.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for StructKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
StructKind::Empty => size_of_val(self),
|
|
||||||
StructKind::Tuple(items) => items.weight_of(),
|
|
||||||
StructKind::Struct(sm) => sm.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for StructMember {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { vis, name, ty } = self;
|
|
||||||
vis.weight_of() + name.weight_of() + ty.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Enum {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, gens, variants } = self;
|
|
||||||
name.weight_of() + gens.weight_of() + variants.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Variant {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, kind, body } = self;
|
|
||||||
name.weight_of() + kind.weight_of() + body.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Impl {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { target, body } = self;
|
|
||||||
target.weight_of() + body.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for ImplKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
ImplKind::Type(ty) => ty.weight_of(),
|
|
||||||
ImplKind::Trait { impl_trait, for_type } => {
|
|
||||||
impl_trait.weight_of() + for_type.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Use {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { absolute, tree } = self;
|
|
||||||
absolute.weight_of() + tree.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for UseTree {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
UseTree::Tree(tr) => tr.weight_of(),
|
|
||||||
UseTree::Path(pa, tr) => pa.weight_of() + tr.weight_of(),
|
|
||||||
UseTree::Alias(src, dst) => src.weight_of() + dst.weight_of(),
|
|
||||||
UseTree::Name(src) => src.weight_of(),
|
|
||||||
UseTree::Glob => size_of_val(self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Ty {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { span, kind } = self;
|
|
||||||
span.weight_of() + kind.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for TyKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
TyKind::Never | TyKind::Empty | TyKind::Infer => size_of_val(self),
|
|
||||||
TyKind::Path(v) => v.weight_of(),
|
|
||||||
TyKind::Array(v) => v.weight_of(),
|
|
||||||
TyKind::Slice(v) => v.weight_of(),
|
|
||||||
TyKind::Tuple(v) => v.weight_of(),
|
|
||||||
TyKind::Ref(v) => v.weight_of(),
|
|
||||||
TyKind::Fn(v) => v.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for TyArray {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { ty, count } = self;
|
|
||||||
ty.weight_of() + count.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for TySlice {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { ty } = self;
|
|
||||||
ty.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for TyTuple {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { types } = self;
|
|
||||||
types.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for TyRef {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { mutable, count, to } = self;
|
|
||||||
mutable.weight_of() + count.weight_of() + to.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for TyFn {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { args, rety } = self;
|
|
||||||
args.weight_of() + rety.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Path {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { absolute, parts } = self;
|
|
||||||
absolute.weight_of() + parts.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for PathPart {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
PathPart::SuperKw => size_of_val(self),
|
|
||||||
PathPart::SelfTy => size_of_val(self),
|
|
||||||
PathPart::Ident(interned) => interned.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Stmt {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { span, kind, semi } = self;
|
|
||||||
span.weight_of() + kind.weight_of() + semi.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for StmtKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
StmtKind::Empty => size_of_val(self),
|
|
||||||
StmtKind::Item(item) => item.weight_of(),
|
|
||||||
StmtKind::Expr(expr) => expr.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Expr {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { span, kind } = self;
|
|
||||||
span.weight_of() + kind.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for ExprKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
ExprKind::Empty => size_of_val(self),
|
|
||||||
ExprKind::Closure(v) => v.weight_of(),
|
|
||||||
ExprKind::Quote(v) => v.weight_of(),
|
|
||||||
ExprKind::Let(v) => v.weight_of(),
|
|
||||||
ExprKind::Match(v) => v.weight_of(),
|
|
||||||
ExprKind::Assign(v) => v.weight_of(),
|
|
||||||
ExprKind::Modify(v) => v.weight_of(),
|
|
||||||
ExprKind::Binary(v) => v.weight_of(),
|
|
||||||
ExprKind::Unary(v) => v.weight_of(),
|
|
||||||
ExprKind::Cast(v) => v.weight_of(),
|
|
||||||
ExprKind::Member(v) => v.weight_of(),
|
|
||||||
ExprKind::Index(v) => v.weight_of(),
|
|
||||||
ExprKind::Structor(v) => v.weight_of(),
|
|
||||||
ExprKind::Path(v) => v.weight_of(),
|
|
||||||
ExprKind::Literal(v) => v.weight_of(),
|
|
||||||
ExprKind::Array(v) => v.weight_of(),
|
|
||||||
ExprKind::ArrayRep(v) => v.weight_of(),
|
|
||||||
ExprKind::AddrOf(v) => v.weight_of(),
|
|
||||||
ExprKind::Block(v) => v.weight_of(),
|
|
||||||
ExprKind::Group(v) => v.weight_of(),
|
|
||||||
ExprKind::Tuple(v) => v.weight_of(),
|
|
||||||
ExprKind::While(v) => v.weight_of(),
|
|
||||||
ExprKind::If(v) => v.weight_of(),
|
|
||||||
ExprKind::For(v) => v.weight_of(),
|
|
||||||
ExprKind::Break(v) => v.weight_of(),
|
|
||||||
ExprKind::Return(v) => v.weight_of(),
|
|
||||||
ExprKind::Continue => size_of_val(self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Closure {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { arg, body } = self;
|
|
||||||
arg.weight_of() + body.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Quote {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { quote } = self;
|
|
||||||
quote.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Let {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { mutable, name, ty, init } = self;
|
|
||||||
mutable.weight_of() + name.weight_of() + ty.weight_of() + init.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Pattern {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
Pattern::Name(s) => size_of_val(s),
|
|
||||||
Pattern::Path(p) => p.weight_of(),
|
|
||||||
Pattern::Literal(literal) => literal.weight_of(),
|
|
||||||
Pattern::Rest(Some(pattern)) => pattern.weight_of(),
|
|
||||||
Pattern::Rest(None) => 0,
|
|
||||||
Pattern::Ref(mutability, pattern) => mutability.weight_of() + pattern.weight_of(),
|
|
||||||
Pattern::RangeExc(head, tail) => head.weight_of() + tail.weight_of(),
|
|
||||||
Pattern::RangeInc(head, tail) => head.weight_of() + tail.weight_of(),
|
|
||||||
Pattern::Tuple(patterns) | Pattern::Array(patterns) => patterns.weight_of(),
|
|
||||||
Pattern::Struct(path, items) => {
|
|
||||||
let sitems: usize = items
|
|
||||||
.iter()
|
|
||||||
.map(|(name, opt)| name.weight_of() + opt.weight_of())
|
|
||||||
.sum();
|
|
||||||
path.weight_of() + sitems
|
|
||||||
}
|
|
||||||
Pattern::TupleStruct(path, patterns) => path.weight_of() + patterns.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Match {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { scrutinee, arms } = self;
|
|
||||||
scrutinee.weight_of() + arms.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for MatchArm {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self(pattern, expr) = self;
|
|
||||||
pattern.weight_of() + expr.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Assign {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { parts } = self;
|
|
||||||
|
|
||||||
parts.0.weight_of() + parts.1.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Modify {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { kind, parts } = self;
|
|
||||||
kind.weight_of()
|
|
||||||
+ parts.0.weight_of()
|
|
||||||
+ parts.1.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Binary {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { kind, parts } = self;
|
|
||||||
|
|
||||||
kind.weight_of() + parts.0.weight_of() + parts.1.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Unary {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { kind, tail } = self;
|
|
||||||
kind.weight_of() + tail.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Cast {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { head, ty } = self;
|
|
||||||
head.weight_of() + ty.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Member {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { head, kind } = self;
|
|
||||||
|
|
||||||
head.weight_of() + kind.weight_of() // accounting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for MemberKind {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
MemberKind::Call(_, tuple) => tuple.weight_of(),
|
|
||||||
MemberKind::Struct(_) => 0,
|
|
||||||
MemberKind::Tuple(literal) => literal.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Index {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { head, indices } = self;
|
|
||||||
head.weight_of() + indices.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Literal {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
Literal::Bool(v) => v.weight_of(),
|
|
||||||
Literal::Char(v) => v.weight_of(),
|
|
||||||
Literal::Int(v) => v.weight_of(),
|
|
||||||
Literal::Float(v) => v.weight_of(),
|
|
||||||
Literal::String(v) => v.weight_of(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Structor {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { to, init } = self;
|
|
||||||
to.weight_of() + init.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Fielder {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { name, init } = self;
|
|
||||||
name.weight_of() + init.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Array {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { values } = self;
|
|
||||||
values.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for ArrayRep {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { value, repeat } = self;
|
|
||||||
value.weight_of() + repeat.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for AddrOf {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { mutable, expr } = self;
|
|
||||||
mutable.weight_of() + expr.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Block {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { stmts } = self;
|
|
||||||
stmts.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Group {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { expr } = self;
|
|
||||||
expr.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Tuple {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { exprs } = self;
|
|
||||||
exprs.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for While {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { cond, pass, fail } = self;
|
|
||||||
cond.weight_of() + pass.weight_of() + fail.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for If {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { cond, pass, fail } = self;
|
|
||||||
cond.weight_of() + pass.weight_of() + fail.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for For {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { bind, cond, pass, fail } = self;
|
|
||||||
bind.weight_of() + cond.weight_of() + pass.weight_of() + fail.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Else {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { body } = self;
|
|
||||||
body.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Break {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { body } = self;
|
|
||||||
body.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for Return {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
let Self { body } = self;
|
|
||||||
body.weight_of()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------ SizeOf Blanket Implementations
|
|
||||||
|
|
||||||
impl<T: WeightOf> WeightOf for Option<T> {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
Some(t) => t.weight_of().max(size_of_val(t)),
|
|
||||||
None => size_of_val(self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeightOf> WeightOf for [T] {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
self.iter().map(WeightOf::weight_of).sum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeightOf> WeightOf for Vec<T> {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
size_of::<Self>() + self.iter().map(WeightOf::weight_of).sum::<usize>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: WeightOf> WeightOf for Box<T> {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
(**self).weight_of() + size_of::<Self>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WeightOf for str {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
self.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_size_of! {
|
|
||||||
// primitives
|
|
||||||
u8, u16, u32, u64, u128, usize,
|
|
||||||
i8, i16, i32, i64, i128, isize,
|
|
||||||
f32, f64, bool, char,
|
|
||||||
// cl-structures
|
|
||||||
Span,
|
|
||||||
// cl-ast
|
|
||||||
Visibility, Mutability, Semi, ModifyKind, BinaryKind, UnaryKind
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> WeightOf for Interned<'_, T> {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
size_of_val(self) // interned values are opaque to SizeOF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro impl_size_of($($T:ty),*$(,)?) {
|
|
||||||
$(impl WeightOf for $T {
|
|
||||||
fn weight_of(&self) -> usize {
|
|
||||||
::std::mem::size_of_val(self)
|
|
||||||
}
|
|
||||||
})*
|
|
||||||
}
|
|
@ -2,11 +2,7 @@
|
|||||||
//! with default implementations across the entire AST
|
//! with default implementations across the entire AST
|
||||||
|
|
||||||
pub mod fold;
|
pub mod fold;
|
||||||
|
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
pub mod walk;
|
|
||||||
|
|
||||||
pub use fold::Fold;
|
pub use fold::Fold;
|
||||||
|
|
||||||
pub use visit::Visit;
|
pub use visit::Visit;
|
||||||
pub use walk::Walk;
|
|
||||||
|
@ -13,8 +13,8 @@ use cl_structures::span::Span;
|
|||||||
///
|
///
|
||||||
/// For all other nodes, traversal is *explicit*.
|
/// For all other nodes, traversal is *explicit*.
|
||||||
pub trait Fold {
|
pub trait Fold {
|
||||||
fn fold_span(&mut self, span: Span) -> Span {
|
fn fold_span(&mut self, extents: Span) -> Span {
|
||||||
span
|
extents
|
||||||
}
|
}
|
||||||
fn fold_mutability(&mut self, mutability: Mutability) -> Mutability {
|
fn fold_mutability(&mut self, mutability: Mutability) -> Mutability {
|
||||||
mutability
|
mutability
|
||||||
@ -44,8 +44,8 @@ pub trait Fold {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
fn fold_file(&mut self, f: File) -> File {
|
fn fold_file(&mut self, f: File) -> File {
|
||||||
let File { name, items } = f;
|
let File { items } = f;
|
||||||
File { name, items: items.into_iter().map(|i| self.fold_item(i)).collect() }
|
File { items: items.into_iter().map(|i| self.fold_item(i)).collect() }
|
||||||
}
|
}
|
||||||
fn fold_attrs(&mut self, a: Attrs) -> Attrs {
|
fn fold_attrs(&mut self, a: Attrs) -> Attrs {
|
||||||
let Attrs { meta } = a;
|
let Attrs { meta } = a;
|
||||||
@ -59,9 +59,9 @@ pub trait Fold {
|
|||||||
or_fold_meta_kind(self, kind)
|
or_fold_meta_kind(self, kind)
|
||||||
}
|
}
|
||||||
fn fold_item(&mut self, i: Item) -> Item {
|
fn fold_item(&mut self, i: Item) -> Item {
|
||||||
let Item { span, attrs, vis, kind } = i;
|
let Item { extents, attrs, vis, kind } = i;
|
||||||
Item {
|
Item {
|
||||||
span: self.fold_span(span),
|
extents: self.fold_span(extents),
|
||||||
attrs: self.fold_attrs(attrs),
|
attrs: self.fold_attrs(attrs),
|
||||||
vis: self.fold_visibility(vis),
|
vis: self.fold_visibility(vis),
|
||||||
kind: self.fold_item_kind(kind),
|
kind: self.fold_item_kind(kind),
|
||||||
@ -70,13 +70,9 @@ pub trait Fold {
|
|||||||
fn fold_item_kind(&mut self, kind: ItemKind) -> ItemKind {
|
fn fold_item_kind(&mut self, kind: ItemKind) -> ItemKind {
|
||||||
or_fold_item_kind(self, kind)
|
or_fold_item_kind(self, kind)
|
||||||
}
|
}
|
||||||
fn fold_generics(&mut self, gens: Generics) -> Generics {
|
|
||||||
let Generics { vars } = gens;
|
|
||||||
Generics { vars: vars.into_iter().map(|sym| self.fold_sym(sym)).collect() }
|
|
||||||
}
|
|
||||||
fn fold_alias(&mut self, a: Alias) -> Alias {
|
fn fold_alias(&mut self, a: Alias) -> Alias {
|
||||||
let Alias { name, from } = a;
|
let Alias { to, from } = a;
|
||||||
Alias { name: self.fold_sym(name), from: from.map(|from| Box::new(self.fold_ty(*from))) }
|
Alias { to: self.fold_sym(to), from: from.map(|from| Box::new(self.fold_ty(*from))) }
|
||||||
}
|
}
|
||||||
fn fold_const(&mut self, c: Const) -> Const {
|
fn fold_const(&mut self, c: Const) -> Const {
|
||||||
let Const { name, ty, init } = c;
|
let Const { name, ty, init } = c;
|
||||||
@ -96,26 +92,31 @@ pub trait Fold {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fold_module(&mut self, m: Module) -> Module {
|
fn fold_module(&mut self, m: Module) -> Module {
|
||||||
let Module { name, file } = m;
|
let Module { name, kind } = m;
|
||||||
Module { name: self.fold_sym(name), file: file.map(|v| self.fold_file(v)) }
|
Module { name: self.fold_sym(name), kind: self.fold_module_kind(kind) }
|
||||||
|
}
|
||||||
|
fn fold_module_kind(&mut self, m: ModuleKind) -> ModuleKind {
|
||||||
|
match m {
|
||||||
|
ModuleKind::Inline(f) => ModuleKind::Inline(self.fold_file(f)),
|
||||||
|
ModuleKind::Outline => ModuleKind::Outline,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn fold_function(&mut self, f: Function) -> Function {
|
fn fold_function(&mut self, f: Function) -> Function {
|
||||||
let Function { name, gens, sign, bind, body } = f;
|
let Function { name, sign, bind, body } = f;
|
||||||
Function {
|
Function {
|
||||||
name: self.fold_sym(name),
|
name: self.fold_sym(name),
|
||||||
gens: self.fold_generics(gens),
|
|
||||||
sign: self.fold_ty_fn(sign),
|
sign: self.fold_ty_fn(sign),
|
||||||
bind: self.fold_pattern(bind),
|
bind: bind.into_iter().map(|p| self.fold_param(p)).collect(),
|
||||||
body: body.map(|b| self.fold_expr(b)),
|
body: body.map(|b| self.fold_block(b)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn fold_param(&mut self, p: Param) -> Param {
|
||||||
|
let Param { mutability, name } = p;
|
||||||
|
Param { mutability: self.fold_mutability(mutability), name: self.fold_sym(name) }
|
||||||
|
}
|
||||||
fn fold_struct(&mut self, s: Struct) -> Struct {
|
fn fold_struct(&mut self, s: Struct) -> Struct {
|
||||||
let Struct { name, gens, kind } = s;
|
let Struct { name, kind } = s;
|
||||||
Struct {
|
Struct { name: self.fold_sym(name), kind: self.fold_struct_kind(kind) }
|
||||||
name: self.fold_sym(name),
|
|
||||||
gens: self.fold_generics(gens),
|
|
||||||
kind: self.fold_struct_kind(kind),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fn fold_struct_kind(&mut self, kind: StructKind) -> StructKind {
|
fn fold_struct_kind(&mut self, kind: StructKind) -> StructKind {
|
||||||
match kind {
|
match kind {
|
||||||
@ -139,21 +140,19 @@ pub trait Fold {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fold_enum(&mut self, e: Enum) -> Enum {
|
fn fold_enum(&mut self, e: Enum) -> Enum {
|
||||||
let Enum { name, gens, variants: kind } = e;
|
let Enum { name, kind } = e;
|
||||||
Enum {
|
Enum { name: self.fold_sym(name), kind: self.fold_enum_kind(kind) }
|
||||||
name: self.fold_sym(name),
|
|
||||||
gens: self.fold_generics(gens),
|
|
||||||
variants: kind.into_iter().map(|v| self.fold_variant(v)).collect(),
|
|
||||||
}
|
}
|
||||||
|
fn fold_enum_kind(&mut self, kind: EnumKind) -> EnumKind {
|
||||||
|
or_fold_enum_kind(self, kind)
|
||||||
}
|
}
|
||||||
fn fold_variant(&mut self, v: Variant) -> Variant {
|
fn fold_variant(&mut self, v: Variant) -> Variant {
|
||||||
let Variant { name, kind, body } = v;
|
let Variant { name, kind } = v;
|
||||||
|
|
||||||
Variant {
|
Variant { name: self.fold_sym(name), kind: self.fold_variant_kind(kind) }
|
||||||
name: self.fold_sym(name),
|
|
||||||
kind: self.fold_struct_kind(kind),
|
|
||||||
body: body.map(|e| Box::new(self.fold_expr(*e))),
|
|
||||||
}
|
}
|
||||||
|
fn fold_variant_kind(&mut self, kind: VariantKind) -> VariantKind {
|
||||||
|
or_fold_variant_kind(self, kind)
|
||||||
}
|
}
|
||||||
fn fold_impl(&mut self, i: Impl) -> Impl {
|
fn fold_impl(&mut self, i: Impl) -> Impl {
|
||||||
let Impl { target, body } = i;
|
let Impl { target, body } = i;
|
||||||
@ -170,8 +169,8 @@ pub trait Fold {
|
|||||||
or_fold_use_tree(self, tree)
|
or_fold_use_tree(self, tree)
|
||||||
}
|
}
|
||||||
fn fold_ty(&mut self, t: Ty) -> Ty {
|
fn fold_ty(&mut self, t: Ty) -> Ty {
|
||||||
let Ty { span, kind } = t;
|
let Ty { extents, kind } = t;
|
||||||
Ty { span: self.fold_span(span), kind: self.fold_ty_kind(kind) }
|
Ty { extents: self.fold_span(extents), kind: self.fold_ty_kind(kind) }
|
||||||
}
|
}
|
||||||
fn fold_ty_kind(&mut self, kind: TyKind) -> TyKind {
|
fn fold_ty_kind(&mut self, kind: TyKind) -> TyKind {
|
||||||
or_fold_ty_kind(self, kind)
|
or_fold_ty_kind(self, kind)
|
||||||
@ -195,7 +194,7 @@ pub trait Fold {
|
|||||||
}
|
}
|
||||||
fn fold_ty_ref(&mut self, t: TyRef) -> TyRef {
|
fn fold_ty_ref(&mut self, t: TyRef) -> TyRef {
|
||||||
let TyRef { mutable, count, to } = t;
|
let TyRef { mutable, count, to } = t;
|
||||||
TyRef { mutable: self.fold_mutability(mutable), count, to: Box::new(self.fold_ty(*to)) }
|
TyRef { mutable: self.fold_mutability(mutable), count, to: self.fold_path(to) }
|
||||||
}
|
}
|
||||||
fn fold_ty_fn(&mut self, t: TyFn) -> TyFn {
|
fn fold_ty_fn(&mut self, t: TyFn) -> TyFn {
|
||||||
let TyFn { args, rety } = t;
|
let TyFn { args, rety } = t;
|
||||||
@ -211,14 +210,15 @@ pub trait Fold {
|
|||||||
fn fold_path_part(&mut self, p: PathPart) -> PathPart {
|
fn fold_path_part(&mut self, p: PathPart) -> PathPart {
|
||||||
match p {
|
match p {
|
||||||
PathPart::SuperKw => PathPart::SuperKw,
|
PathPart::SuperKw => PathPart::SuperKw,
|
||||||
|
PathPart::SelfKw => PathPart::SelfKw,
|
||||||
PathPart::SelfTy => PathPart::SelfTy,
|
PathPart::SelfTy => PathPart::SelfTy,
|
||||||
PathPart::Ident(i) => PathPart::Ident(self.fold_sym(i)),
|
PathPart::Ident(i) => PathPart::Ident(self.fold_sym(i)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fold_stmt(&mut self, s: Stmt) -> Stmt {
|
fn fold_stmt(&mut self, s: Stmt) -> Stmt {
|
||||||
let Stmt { span, kind, semi } = s;
|
let Stmt { extents, kind, semi } = s;
|
||||||
Stmt {
|
Stmt {
|
||||||
span: self.fold_span(span),
|
extents: self.fold_span(extents),
|
||||||
kind: self.fold_stmt_kind(kind),
|
kind: self.fold_stmt_kind(kind),
|
||||||
semi: self.fold_semi(semi),
|
semi: self.fold_semi(semi),
|
||||||
}
|
}
|
||||||
@ -230,16 +230,12 @@ pub trait Fold {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
fn fold_expr(&mut self, e: Expr) -> Expr {
|
fn fold_expr(&mut self, e: Expr) -> Expr {
|
||||||
let Expr { span, kind } = e;
|
let Expr { extents, kind } = e;
|
||||||
Expr { span: self.fold_span(span), kind: self.fold_expr_kind(kind) }
|
Expr { extents: self.fold_span(extents), kind: self.fold_expr_kind(kind) }
|
||||||
}
|
}
|
||||||
fn fold_expr_kind(&mut self, kind: ExprKind) -> ExprKind {
|
fn fold_expr_kind(&mut self, kind: ExprKind) -> ExprKind {
|
||||||
or_fold_expr_kind(self, kind)
|
or_fold_expr_kind(self, kind)
|
||||||
}
|
}
|
||||||
fn fold_closure(&mut self, value: Closure) -> Closure {
|
|
||||||
let Closure { arg, body } = value;
|
|
||||||
Closure { arg: Box::new(self.fold_pattern(*arg)), body: Box::new(self.fold_expr(*body)) }
|
|
||||||
}
|
|
||||||
fn fold_let(&mut self, l: Let) -> Let {
|
fn fold_let(&mut self, l: Let) -> Let {
|
||||||
let Let { mutable, name, ty, init } = l;
|
let Let { mutable, name, ty, init } = l;
|
||||||
Let {
|
Let {
|
||||||
@ -252,23 +248,12 @@ pub trait Fold {
|
|||||||
|
|
||||||
fn fold_pattern(&mut self, p: Pattern) -> Pattern {
|
fn fold_pattern(&mut self, p: Pattern) -> Pattern {
|
||||||
match p {
|
match p {
|
||||||
Pattern::Name(sym) => Pattern::Name(self.fold_sym(sym)),
|
|
||||||
Pattern::Path(path) => Pattern::Path(self.fold_path(path)),
|
Pattern::Path(path) => Pattern::Path(self.fold_path(path)),
|
||||||
Pattern::Literal(literal) => Pattern::Literal(self.fold_literal(literal)),
|
Pattern::Literal(literal) => Pattern::Literal(self.fold_literal(literal)),
|
||||||
Pattern::Rest(Some(name)) => Pattern::Rest(Some(self.fold_pattern(*name).into())),
|
|
||||||
Pattern::Rest(None) => Pattern::Rest(None),
|
|
||||||
Pattern::Ref(mutability, pattern) => Pattern::Ref(
|
Pattern::Ref(mutability, pattern) => Pattern::Ref(
|
||||||
self.fold_mutability(mutability),
|
self.fold_mutability(mutability),
|
||||||
Box::new(self.fold_pattern(*pattern)),
|
Box::new(self.fold_pattern(*pattern)),
|
||||||
),
|
),
|
||||||
Pattern::RangeExc(head, tail) => Pattern::RangeInc(
|
|
||||||
Box::new(self.fold_pattern(*head)),
|
|
||||||
Box::new(self.fold_pattern(*tail)),
|
|
||||||
),
|
|
||||||
Pattern::RangeInc(head, tail) => Pattern::RangeInc(
|
|
||||||
Box::new(self.fold_pattern(*head)),
|
|
||||||
Box::new(self.fold_pattern(*tail)),
|
|
||||||
),
|
|
||||||
Pattern::Tuple(patterns) => {
|
Pattern::Tuple(patterns) => {
|
||||||
Pattern::Tuple(patterns.into_iter().map(|p| self.fold_pattern(p)).collect())
|
Pattern::Tuple(patterns.into_iter().map(|p| self.fold_pattern(p)).collect())
|
||||||
}
|
}
|
||||||
@ -282,13 +267,6 @@ pub trait Fold {
|
|||||||
.map(|(name, bind)| (name, bind.map(|p| self.fold_pattern(p))))
|
.map(|(name, bind)| (name, bind.map(|p| self.fold_pattern(p))))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
Pattern::TupleStruct(path, items) => Pattern::TupleStruct(
|
|
||||||
self.fold_path(path),
|
|
||||||
items
|
|
||||||
.into_iter()
|
|
||||||
.map(|bind| self.fold_pattern(bind))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,14 +289,14 @@ pub trait Fold {
|
|||||||
fn fold_assign(&mut self, a: Assign) -> Assign {
|
fn fold_assign(&mut self, a: Assign) -> Assign {
|
||||||
let Assign { parts } = a;
|
let Assign { parts } = a;
|
||||||
let (head, tail) = *parts;
|
let (head, tail) = *parts;
|
||||||
Assign { parts: Box::new((self.fold_expr(head), self.fold_expr(tail))) }
|
Assign { parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))) }
|
||||||
}
|
}
|
||||||
fn fold_modify(&mut self, m: Modify) -> Modify {
|
fn fold_modify(&mut self, m: Modify) -> Modify {
|
||||||
let Modify { kind, parts } = m;
|
let Modify { kind, parts } = m;
|
||||||
let (head, tail) = *parts;
|
let (head, tail) = *parts;
|
||||||
Modify {
|
Modify {
|
||||||
kind: self.fold_modify_kind(kind),
|
kind: self.fold_modify_kind(kind),
|
||||||
parts: Box::new((self.fold_expr(head), self.fold_expr(tail))),
|
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fold_modify_kind(&mut self, kind: ModifyKind) -> ModifyKind {
|
fn fold_modify_kind(&mut self, kind: ModifyKind) -> ModifyKind {
|
||||||
@ -329,7 +307,7 @@ pub trait Fold {
|
|||||||
let (head, tail) = *parts;
|
let (head, tail) = *parts;
|
||||||
Binary {
|
Binary {
|
||||||
kind: self.fold_binary_kind(kind),
|
kind: self.fold_binary_kind(kind),
|
||||||
parts: Box::new((self.fold_expr(head), self.fold_expr(tail))),
|
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn fold_binary_kind(&mut self, kind: BinaryKind) -> BinaryKind {
|
fn fold_binary_kind(&mut self, kind: BinaryKind) -> BinaryKind {
|
||||||
@ -337,18 +315,18 @@ pub trait Fold {
|
|||||||
}
|
}
|
||||||
fn fold_unary(&mut self, u: Unary) -> Unary {
|
fn fold_unary(&mut self, u: Unary) -> Unary {
|
||||||
let Unary { kind, tail } = u;
|
let Unary { kind, tail } = u;
|
||||||
Unary { kind: self.fold_unary_kind(kind), tail: Box::new(self.fold_expr(*tail)) }
|
Unary { kind: self.fold_unary_kind(kind), tail: Box::new(self.fold_expr_kind(*tail)) }
|
||||||
}
|
}
|
||||||
fn fold_unary_kind(&mut self, kind: UnaryKind) -> UnaryKind {
|
fn fold_unary_kind(&mut self, kind: UnaryKind) -> UnaryKind {
|
||||||
kind
|
kind
|
||||||
}
|
}
|
||||||
fn fold_cast(&mut self, cast: Cast) -> Cast {
|
fn fold_cast(&mut self, cast: Cast) -> Cast {
|
||||||
let Cast { head, ty } = cast;
|
let Cast { head, ty } = cast;
|
||||||
Cast { head: Box::new(self.fold_expr(*head)), ty: self.fold_ty(ty) }
|
Cast { head: Box::new(self.fold_expr_kind(*head)), ty: self.fold_ty(ty) }
|
||||||
}
|
}
|
||||||
fn fold_member(&mut self, m: Member) -> Member {
|
fn fold_member(&mut self, m: Member) -> Member {
|
||||||
let Member { head, kind } = m;
|
let Member { head, kind } = m;
|
||||||
Member { head: Box::new(self.fold_expr(*head)), kind: self.fold_member_kind(kind) }
|
Member { head: Box::new(self.fold_expr_kind(*head)), kind: self.fold_member_kind(kind) }
|
||||||
}
|
}
|
||||||
fn fold_member_kind(&mut self, kind: MemberKind) -> MemberKind {
|
fn fold_member_kind(&mut self, kind: MemberKind) -> MemberKind {
|
||||||
or_fold_member_kind(self, kind)
|
or_fold_member_kind(self, kind)
|
||||||
@ -356,7 +334,7 @@ pub trait Fold {
|
|||||||
fn fold_index(&mut self, i: Index) -> Index {
|
fn fold_index(&mut self, i: Index) -> Index {
|
||||||
let Index { head, indices } = i;
|
let Index { head, indices } = i;
|
||||||
Index {
|
Index {
|
||||||
head: Box::new(self.fold_expr(*head)),
|
head: Box::new(self.fold_expr_kind(*head)),
|
||||||
indices: indices.into_iter().map(|e| self.fold_expr(e)).collect(),
|
indices: indices.into_iter().map(|e| self.fold_expr(e)).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,11 +357,17 @@ pub trait Fold {
|
|||||||
}
|
}
|
||||||
fn fold_array_rep(&mut self, a: ArrayRep) -> ArrayRep {
|
fn fold_array_rep(&mut self, a: ArrayRep) -> ArrayRep {
|
||||||
let ArrayRep { value, repeat } = a;
|
let ArrayRep { value, repeat } = a;
|
||||||
ArrayRep { value: Box::new(self.fold_expr(*value)), repeat }
|
ArrayRep {
|
||||||
|
value: Box::new(self.fold_expr_kind(*value)),
|
||||||
|
repeat: Box::new(self.fold_expr_kind(*repeat)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn fold_addrof(&mut self, a: AddrOf) -> AddrOf {
|
fn fold_addrof(&mut self, a: AddrOf) -> AddrOf {
|
||||||
let AddrOf { mutable, expr } = a;
|
let AddrOf { mutable, expr } = a;
|
||||||
AddrOf { mutable: self.fold_mutability(mutable), expr: Box::new(self.fold_expr(*expr)) }
|
AddrOf {
|
||||||
|
mutable: self.fold_mutability(mutable),
|
||||||
|
expr: Box::new(self.fold_expr_kind(*expr)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn fold_block(&mut self, b: Block) -> Block {
|
fn fold_block(&mut self, b: Block) -> Block {
|
||||||
let Block { stmts } = b;
|
let Block { stmts } = b;
|
||||||
@ -391,7 +375,7 @@ pub trait Fold {
|
|||||||
}
|
}
|
||||||
fn fold_group(&mut self, g: Group) -> Group {
|
fn fold_group(&mut self, g: Group) -> Group {
|
||||||
let Group { expr } = g;
|
let Group { expr } = g;
|
||||||
Group { expr: Box::new(self.fold_expr(*expr)) }
|
Group { expr: Box::new(self.fold_expr_kind(*expr)) }
|
||||||
}
|
}
|
||||||
fn fold_tuple(&mut self, t: Tuple) -> Tuple {
|
fn fold_tuple(&mut self, t: Tuple) -> Tuple {
|
||||||
let Tuple { exprs } = t;
|
let Tuple { exprs } = t;
|
||||||
@ -416,7 +400,7 @@ pub trait Fold {
|
|||||||
fn fold_for(&mut self, f: For) -> For {
|
fn fold_for(&mut self, f: For) -> For {
|
||||||
let For { bind, cond, pass, fail } = f;
|
let For { bind, cond, pass, fail } = f;
|
||||||
For {
|
For {
|
||||||
bind: self.fold_pattern(bind),
|
bind: self.fold_sym(bind),
|
||||||
cond: Box::new(self.fold_expr(*cond)),
|
cond: Box::new(self.fold_expr(*cond)),
|
||||||
pass: Box::new(self.fold_block(*pass)),
|
pass: Box::new(self.fold_block(*pass)),
|
||||||
fail: self.fold_else(fail),
|
fail: self.fold_else(fail),
|
||||||
@ -476,6 +460,15 @@ pub fn or_fold_item_kind<F: Fold + ?Sized>(folder: &mut F, kind: ItemKind) -> It
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Folds a [ModuleKind] in the default way
|
||||||
|
pub fn or_fold_module_kind<F: Fold + ?Sized>(folder: &mut F, kind: ModuleKind) -> ModuleKind {
|
||||||
|
match kind {
|
||||||
|
ModuleKind::Inline(f) => ModuleKind::Inline(folder.fold_file(f)),
|
||||||
|
ModuleKind::Outline => ModuleKind::Outline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Folds a [StructKind] in the default way
|
/// Folds a [StructKind] in the default way
|
||||||
pub fn or_fold_struct_kind<F: Fold + ?Sized>(folder: &mut F, kind: StructKind) -> StructKind {
|
pub fn or_fold_struct_kind<F: Fold + ?Sized>(folder: &mut F, kind: StructKind) -> StructKind {
|
||||||
@ -492,6 +485,32 @@ pub fn or_fold_struct_kind<F: Fold + ?Sized>(folder: &mut F, kind: StructKind) -
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Folds an [EnumKind] in the default way
|
||||||
|
pub fn or_fold_enum_kind<F: Fold + ?Sized>(folder: &mut F, kind: EnumKind) -> EnumKind {
|
||||||
|
match kind {
|
||||||
|
EnumKind::NoVariants => EnumKind::NoVariants,
|
||||||
|
EnumKind::Variants(v) => {
|
||||||
|
EnumKind::Variants(v.into_iter().map(|v| folder.fold_variant(v)).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Folds a [VariantKind] in the default way
|
||||||
|
pub fn or_fold_variant_kind<F: Fold + ?Sized>(folder: &mut F, kind: VariantKind) -> VariantKind {
|
||||||
|
match kind {
|
||||||
|
VariantKind::Plain => VariantKind::Plain,
|
||||||
|
VariantKind::CLike(n) => VariantKind::CLike(n),
|
||||||
|
VariantKind::Tuple(t) => VariantKind::Tuple(folder.fold_ty(t)),
|
||||||
|
VariantKind::Struct(mem) => VariantKind::Struct(
|
||||||
|
mem.into_iter()
|
||||||
|
.map(|m| folder.fold_struct_member(m))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Folds an [ImplKind] in the default way
|
/// Folds an [ImplKind] in the default way
|
||||||
pub fn or_fold_impl_kind<F: Fold + ?Sized>(folder: &mut F, kind: ImplKind) -> ImplKind {
|
pub fn or_fold_impl_kind<F: Fold + ?Sized>(folder: &mut F, kind: ImplKind) -> ImplKind {
|
||||||
@ -528,7 +547,6 @@ pub fn or_fold_ty_kind<F: Fold + ?Sized>(folder: &mut F, kind: TyKind) -> TyKind
|
|||||||
match kind {
|
match kind {
|
||||||
TyKind::Never => TyKind::Never,
|
TyKind::Never => TyKind::Never,
|
||||||
TyKind::Empty => TyKind::Empty,
|
TyKind::Empty => TyKind::Empty,
|
||||||
TyKind::Infer => TyKind::Infer,
|
|
||||||
TyKind::Path(p) => TyKind::Path(folder.fold_path(p)),
|
TyKind::Path(p) => TyKind::Path(folder.fold_path(p)),
|
||||||
TyKind::Array(a) => TyKind::Array(folder.fold_ty_array(a)),
|
TyKind::Array(a) => TyKind::Array(folder.fold_ty_array(a)),
|
||||||
TyKind::Slice(s) => TyKind::Slice(folder.fold_ty_slice(s)),
|
TyKind::Slice(s) => TyKind::Slice(folder.fold_ty_slice(s)),
|
||||||
@ -552,7 +570,6 @@ pub fn or_fold_stmt_kind<F: Fold + ?Sized>(folder: &mut F, kind: StmtKind) -> St
|
|||||||
pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> ExprKind {
|
pub fn or_fold_expr_kind<F: Fold + ?Sized>(folder: &mut F, kind: ExprKind) -> ExprKind {
|
||||||
match kind {
|
match kind {
|
||||||
ExprKind::Empty => ExprKind::Empty,
|
ExprKind::Empty => ExprKind::Empty,
|
||||||
ExprKind::Closure(c) => ExprKind::Closure(folder.fold_closure(c)),
|
|
||||||
ExprKind::Quote(q) => ExprKind::Quote(q), // quoted expressions are left unmodified
|
ExprKind::Quote(q) => ExprKind::Quote(q), // quoted expressions are left unmodified
|
||||||
ExprKind::Let(l) => ExprKind::Let(folder.fold_let(l)),
|
ExprKind::Let(l) => ExprKind::Let(folder.fold_let(l)),
|
||||||
ExprKind::Match(m) => ExprKind::Match(folder.fold_match(m)),
|
ExprKind::Match(m) => ExprKind::Match(folder.fold_match(m)),
|
||||||
|
@ -3,255 +3,527 @@
|
|||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use cl_structures::span::Span;
|
use cl_structures::span::Span;
|
||||||
|
|
||||||
use super::walk::Walk;
|
|
||||||
|
|
||||||
/// Immutably walks the entire AST
|
/// Immutably walks the entire AST
|
||||||
///
|
///
|
||||||
/// Each method acts as a customization point.
|
/// Each method acts as a customization point.
|
||||||
|
///
|
||||||
|
/// There are a set of default implementations for enums
|
||||||
|
/// under the name [`or_visit_`*](or_visit_expr_kind),
|
||||||
|
/// provided for ease of use.
|
||||||
|
///
|
||||||
|
/// For all other nodes, traversal is *explicit*.
|
||||||
pub trait Visit<'a>: Sized {
|
pub trait Visit<'a>: Sized {
|
||||||
/// Visits a [Walker](Walk)
|
fn visit_span(&mut self, _extents: &'a Span) {}
|
||||||
#[inline]
|
fn visit_mutability(&mut self, _mutable: &'a Mutability) {}
|
||||||
fn visit<W: Walk>(&mut self, walker: &'a W) -> &mut Self {
|
fn visit_visibility(&mut self, _vis: &'a Visibility) {}
|
||||||
walker.visit_in(self);
|
fn visit_sym(&mut self, _name: &'a Sym) {}
|
||||||
self
|
fn visit_literal(&mut self, l: &'a Literal) {
|
||||||
|
or_visit_literal(self, l)
|
||||||
|
}
|
||||||
|
fn visit_bool(&mut self, _b: &'a bool) {}
|
||||||
|
fn visit_char(&mut self, _c: &'a char) {}
|
||||||
|
fn visit_int(&mut self, _i: &'a u128) {}
|
||||||
|
fn visit_smuggled_float(&mut self, _f: &'a u64) {}
|
||||||
|
fn visit_string(&mut self, _s: &'a str) {}
|
||||||
|
fn visit_file(&mut self, f: &'a File) {
|
||||||
|
let File { items } = f;
|
||||||
|
items.iter().for_each(|i| self.visit_item(i));
|
||||||
|
}
|
||||||
|
fn visit_attrs(&mut self, a: &'a Attrs) {
|
||||||
|
let Attrs { meta } = a;
|
||||||
|
meta.iter().for_each(|m| self.visit_meta(m));
|
||||||
|
}
|
||||||
|
fn visit_meta(&mut self, m: &'a Meta) {
|
||||||
|
let Meta { name, kind } = m;
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_meta_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_meta_kind(&mut self, kind: &'a MetaKind) {
|
||||||
|
or_visit_meta_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_item(&mut self, i: &'a Item) {
|
||||||
|
let Item { extents, attrs, vis, kind } = i;
|
||||||
|
self.visit_span(extents);
|
||||||
|
self.visit_attrs(attrs);
|
||||||
|
self.visit_visibility(vis);
|
||||||
|
self.visit_item_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_item_kind(&mut self, kind: &'a ItemKind) {
|
||||||
|
or_visit_item_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_alias(&mut self, a: &'a Alias) {
|
||||||
|
let Alias { to, from } = a;
|
||||||
|
self.visit_sym(to);
|
||||||
|
if let Some(t) = from {
|
||||||
|
self.visit_ty(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_const(&mut self, c: &'a Const) {
|
||||||
|
let Const { name, ty, init } = c;
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_ty(ty);
|
||||||
|
self.visit_expr(init);
|
||||||
|
}
|
||||||
|
fn visit_static(&mut self, s: &'a Static) {
|
||||||
|
let Static { mutable, name, ty, init } = s;
|
||||||
|
self.visit_mutability(mutable);
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_ty(ty);
|
||||||
|
self.visit_expr(init);
|
||||||
|
}
|
||||||
|
fn visit_module(&mut self, m: &'a Module) {
|
||||||
|
let Module { name, kind } = m;
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_module_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_module_kind(&mut self, kind: &'a ModuleKind) {
|
||||||
|
or_visit_module_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_function(&mut self, f: &'a Function) {
|
||||||
|
let Function { name, sign, bind, body } = f;
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_ty_fn(sign);
|
||||||
|
bind.iter().for_each(|p| self.visit_param(p));
|
||||||
|
if let Some(b) = body {
|
||||||
|
self.visit_block(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_param(&mut self, p: &'a Param) {
|
||||||
|
let Param { mutability, name } = p;
|
||||||
|
self.visit_mutability(mutability);
|
||||||
|
self.visit_sym(name);
|
||||||
|
}
|
||||||
|
fn visit_struct(&mut self, s: &'a Struct) {
|
||||||
|
let Struct { name, kind } = s;
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_struct_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_struct_kind(&mut self, kind: &'a StructKind) {
|
||||||
|
or_visit_struct_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_struct_member(&mut self, m: &'a StructMember) {
|
||||||
|
let StructMember { vis, name, ty } = m;
|
||||||
|
self.visit_visibility(vis);
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_ty(ty);
|
||||||
|
}
|
||||||
|
fn visit_enum(&mut self, e: &'a Enum) {
|
||||||
|
let Enum { name, kind } = e;
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_enum_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_enum_kind(&mut self, kind: &'a EnumKind) {
|
||||||
|
or_visit_enum_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_variant(&mut self, v: &'a Variant) {
|
||||||
|
let Variant { name, kind } = v;
|
||||||
|
self.visit_sym(name);
|
||||||
|
self.visit_variant_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_variant_kind(&mut self, kind: &'a VariantKind) {
|
||||||
|
or_visit_variant_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_impl(&mut self, i: &'a Impl) {
|
||||||
|
let Impl { target, body } = i;
|
||||||
|
self.visit_impl_kind(target);
|
||||||
|
self.visit_file(body);
|
||||||
|
}
|
||||||
|
fn visit_impl_kind(&mut self, target: &'a ImplKind) {
|
||||||
|
or_visit_impl_kind(self, target)
|
||||||
|
}
|
||||||
|
fn visit_use(&mut self, u: &'a Use) {
|
||||||
|
let Use { absolute: _, tree } = u;
|
||||||
|
self.visit_use_tree(tree);
|
||||||
|
}
|
||||||
|
fn visit_use_tree(&mut self, tree: &'a UseTree) {
|
||||||
|
or_visit_use_tree(self, tree)
|
||||||
|
}
|
||||||
|
fn visit_ty(&mut self, t: &'a Ty) {
|
||||||
|
let Ty { extents, kind } = t;
|
||||||
|
self.visit_span(extents);
|
||||||
|
self.visit_ty_kind(kind);
|
||||||
|
}
|
||||||
|
fn visit_ty_kind(&mut self, kind: &'a TyKind) {
|
||||||
|
or_visit_ty_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_ty_array(&mut self, a: &'a TyArray) {
|
||||||
|
let TyArray { ty, count: _ } = a;
|
||||||
|
self.visit_ty_kind(ty);
|
||||||
|
}
|
||||||
|
fn visit_ty_slice(&mut self, s: &'a TySlice) {
|
||||||
|
let TySlice { ty } = s;
|
||||||
|
self.visit_ty_kind(ty)
|
||||||
|
}
|
||||||
|
fn visit_ty_tuple(&mut self, t: &'a TyTuple) {
|
||||||
|
let TyTuple { types } = t;
|
||||||
|
types.iter().for_each(|kind| self.visit_ty_kind(kind))
|
||||||
|
}
|
||||||
|
fn visit_ty_ref(&mut self, t: &'a TyRef) {
|
||||||
|
let TyRef { mutable, count: _, to } = t;
|
||||||
|
self.visit_mutability(mutable);
|
||||||
|
self.visit_path(to);
|
||||||
|
}
|
||||||
|
fn visit_ty_fn(&mut self, t: &'a TyFn) {
|
||||||
|
let TyFn { args, rety } = t;
|
||||||
|
self.visit_ty_kind(args);
|
||||||
|
if let Some(rety) = rety {
|
||||||
|
self.visit_ty(rety);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_path(&mut self, p: &'a Path) {
|
||||||
|
let Path { absolute: _, parts } = p;
|
||||||
|
parts.iter().for_each(|p| self.visit_path_part(p))
|
||||||
|
}
|
||||||
|
fn visit_path_part(&mut self, p: &'a PathPart) {
|
||||||
|
match p {
|
||||||
|
PathPart::SuperKw => {}
|
||||||
|
PathPart::SelfKw => {}
|
||||||
|
PathPart::SelfTy => {}
|
||||||
|
PathPart::Ident(i) => self.visit_sym(i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn visit_stmt(&mut self, s: &'a Stmt) {
|
||||||
|
let Stmt { extents, kind, semi } = s;
|
||||||
|
self.visit_span(extents);
|
||||||
|
self.visit_stmt_kind(kind);
|
||||||
|
self.visit_semi(semi);
|
||||||
|
}
|
||||||
|
fn visit_stmt_kind(&mut self, kind: &'a StmtKind) {
|
||||||
|
or_visit_stmt_kind(self, kind)
|
||||||
|
}
|
||||||
|
fn visit_semi(&mut self, _s: &'a Semi) {}
|
||||||
|
fn visit_expr(&mut self, e: &'a Expr) {
|
||||||
|
let Expr { extents, kind } = e;
|
||||||
|
self.visit_span(extents);
|
||||||
|
self.visit_expr_kind(kind)
|
||||||
|
}
|
||||||
|
fn visit_expr_kind(&mut self, e: &'a ExprKind) {
|
||||||
|
or_visit_expr_kind(self, e)
|
||||||
|
}
|
||||||
|
fn visit_let(&mut self, l: &'a Let) {
|
||||||
|
let Let { mutable, name, ty, init } = l;
|
||||||
|
self.visit_mutability(mutable);
|
||||||
|
self.visit_pattern(name);
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
self.visit_ty(ty);
|
||||||
|
}
|
||||||
|
if let Some(init) = init {
|
||||||
|
self.visit_expr(init)
|
||||||
}
|
}
|
||||||
/// Visits the children of a [Walker](Walk)
|
|
||||||
fn visit_children<W: Walk>(&mut self, walker: &'a W) {
|
|
||||||
walker.children(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_span(&mut self, value: &'a Span) {
|
fn visit_pattern(&mut self, p: &'a Pattern) {
|
||||||
value.children(self)
|
match p {
|
||||||
|
Pattern::Path(path) => self.visit_path(path),
|
||||||
|
Pattern::Literal(literal) => self.visit_literal(literal),
|
||||||
|
Pattern::Ref(mutability, pattern) => {
|
||||||
|
self.visit_mutability(mutability);
|
||||||
|
self.visit_pattern(pattern);
|
||||||
}
|
}
|
||||||
fn visit_mutability(&mut self, value: &'a Mutability) {
|
Pattern::Tuple(patterns) => {
|
||||||
value.children(self)
|
patterns.iter().for_each(|p| self.visit_pattern(p));
|
||||||
}
|
}
|
||||||
fn visit_visibility(&mut self, value: &'a Visibility) {
|
Pattern::Array(patterns) => {
|
||||||
value.children(self)
|
patterns.iter().for_each(|p| self.visit_pattern(p));
|
||||||
}
|
}
|
||||||
fn visit_sym(&mut self, value: &'a Sym) {
|
Pattern::Struct(path, items) => {
|
||||||
value.children(self)
|
self.visit_path(path);
|
||||||
|
items.iter().for_each(|(_name, bind)| {
|
||||||
|
bind.as_ref().inspect(|bind| {
|
||||||
|
self.visit_pattern(bind);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
fn visit_literal(&mut self, value: &'a Literal) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
}
|
||||||
fn visit_bool(&mut self, value: &'a bool) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_char(&mut self, value: &'a char) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_int(&mut self, value: &'a u128) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_smuggled_float(&mut self, value: &'a u64) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_string(&mut self, value: &'a str) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_file(&mut self, value: &'a File) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_attrs(&mut self, value: &'a Attrs) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_meta(&mut self, value: &'a Meta) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_meta_kind(&mut self, value: &'a MetaKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_item(&mut self, value: &'a Item) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_item_kind(&mut self, value: &'a ItemKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_generics(&mut self, value: &'a Generics) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_alias(&mut self, value: &'a Alias) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_const(&mut self, value: &'a Const) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_static(&mut self, value: &'a Static) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_module(&mut self, value: &'a Module) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_function(&mut self, value: &'a Function) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_struct(&mut self, value: &'a Struct) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_struct_kind(&mut self, value: &'a StructKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_struct_member(&mut self, value: &'a StructMember) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_enum(&mut self, value: &'a Enum) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_variant(&mut self, value: &'a Variant) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_impl(&mut self, value: &'a Impl) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_impl_kind(&mut self, value: &'a ImplKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_use(&mut self, value: &'a Use) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_use_tree(&mut self, value: &'a UseTree) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_ty(&mut self, value: &'a Ty) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_ty_kind(&mut self, value: &'a TyKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_ty_array(&mut self, value: &'a TyArray) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_ty_slice(&mut self, value: &'a TySlice) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_ty_tuple(&mut self, value: &'a TyTuple) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_ty_ref(&mut self, value: &'a TyRef) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_ty_fn(&mut self, value: &'a TyFn) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_path(&mut self, value: &'a Path) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_path_part(&mut self, value: &'a PathPart) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_stmt(&mut self, value: &'a Stmt) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_stmt_kind(&mut self, value: &'a StmtKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_semi(&mut self, value: &'a Semi) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_expr(&mut self, value: &'a Expr) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_expr_kind(&mut self, value: &'a ExprKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_closure(&mut self, value: &'a Closure) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_quote(&mut self, value: &'a Quote) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
|
||||||
fn visit_let(&mut self, value: &'a Let) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_pattern(&mut self, value: &'a Pattern) {
|
fn visit_match(&mut self, m: &'a Match) {
|
||||||
value.children(self)
|
let Match { scrutinee, arms } = m;
|
||||||
|
self.visit_expr(scrutinee);
|
||||||
|
arms.iter().for_each(|arm| self.visit_match_arm(arm));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_match(&mut self, value: &'a Match) {
|
fn visit_match_arm(&mut self, a: &'a MatchArm) {
|
||||||
value.children(self)
|
let MatchArm(pat, expr) = a;
|
||||||
|
self.visit_pattern(pat);
|
||||||
|
self.visit_expr(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_match_arm(&mut self, value: &'a MatchArm) {
|
fn visit_assign(&mut self, a: &'a Assign) {
|
||||||
value.children(self)
|
let Assign { parts } = a;
|
||||||
|
let (head, tail) = parts.as_ref();
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
self.visit_expr_kind(tail);
|
||||||
}
|
}
|
||||||
|
fn visit_modify(&mut self, m: &'a Modify) {
|
||||||
fn visit_assign(&mut self, value: &'a Assign) {
|
let Modify { kind, parts } = m;
|
||||||
value.children(self)
|
let (head, tail) = parts.as_ref();
|
||||||
|
self.visit_modify_kind(kind);
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
self.visit_expr_kind(tail);
|
||||||
}
|
}
|
||||||
fn visit_modify(&mut self, value: &'a Modify) {
|
fn visit_modify_kind(&mut self, _kind: &'a ModifyKind) {}
|
||||||
value.children(self)
|
fn visit_binary(&mut self, b: &'a Binary) {
|
||||||
|
let Binary { kind, parts } = b;
|
||||||
|
let (head, tail) = parts.as_ref();
|
||||||
|
self.visit_binary_kind(kind);
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
self.visit_expr_kind(tail);
|
||||||
}
|
}
|
||||||
fn visit_modify_kind(&mut self, value: &'a ModifyKind) {
|
fn visit_binary_kind(&mut self, _kind: &'a BinaryKind) {}
|
||||||
value.children(self)
|
fn visit_unary(&mut self, u: &'a Unary) {
|
||||||
|
let Unary { kind, tail } = u;
|
||||||
|
self.visit_unary_kind(kind);
|
||||||
|
self.visit_expr_kind(tail);
|
||||||
}
|
}
|
||||||
fn visit_binary(&mut self, value: &'a Binary) {
|
fn visit_unary_kind(&mut self, _kind: &'a UnaryKind) {}
|
||||||
value.children(self)
|
fn visit_cast(&mut self, cast: &'a Cast) {
|
||||||
|
let Cast { head, ty } = cast;
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
self.visit_ty(ty);
|
||||||
}
|
}
|
||||||
fn visit_binary_kind(&mut self, value: &'a BinaryKind) {
|
fn visit_member(&mut self, m: &'a Member) {
|
||||||
value.children(self)
|
let Member { head, kind } = m;
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
self.visit_member_kind(kind);
|
||||||
}
|
}
|
||||||
fn visit_unary(&mut self, value: &'a Unary) {
|
fn visit_member_kind(&mut self, kind: &'a MemberKind) {
|
||||||
value.children(self)
|
or_visit_member_kind(self, kind)
|
||||||
}
|
}
|
||||||
fn visit_unary_kind(&mut self, value: &'a UnaryKind) {
|
fn visit_index(&mut self, i: &'a Index) {
|
||||||
value.children(self)
|
let Index { head, indices } = i;
|
||||||
|
self.visit_expr_kind(head);
|
||||||
|
indices.iter().for_each(|e| self.visit_expr(e));
|
||||||
}
|
}
|
||||||
|
fn visit_structor(&mut self, s: &'a Structor) {
|
||||||
fn visit_cast(&mut self, value: &'a Cast) {
|
let Structor { to, init } = s;
|
||||||
value.children(self)
|
self.visit_path(to);
|
||||||
|
init.iter().for_each(|e| self.visit_fielder(e))
|
||||||
}
|
}
|
||||||
fn visit_member(&mut self, value: &'a Member) {
|
fn visit_fielder(&mut self, f: &'a Fielder) {
|
||||||
value.children(self)
|
let Fielder { name, init } = f;
|
||||||
|
self.visit_sym(name);
|
||||||
|
if let Some(init) = init {
|
||||||
|
self.visit_expr(init);
|
||||||
}
|
}
|
||||||
fn visit_member_kind(&mut self, value: &'a MemberKind) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
}
|
||||||
fn visit_index(&mut self, value: &'a Index) {
|
fn visit_array(&mut self, a: &'a Array) {
|
||||||
value.children(self)
|
let Array { values } = a;
|
||||||
|
values.iter().for_each(|e| self.visit_expr(e))
|
||||||
}
|
}
|
||||||
fn visit_structor(&mut self, value: &'a Structor) {
|
fn visit_array_rep(&mut self, a: &'a ArrayRep) {
|
||||||
value.children(self)
|
let ArrayRep { value, repeat } = a;
|
||||||
|
self.visit_expr_kind(value);
|
||||||
|
self.visit_expr_kind(repeat);
|
||||||
}
|
}
|
||||||
fn visit_fielder(&mut self, value: &'a Fielder) {
|
fn visit_addrof(&mut self, a: &'a AddrOf) {
|
||||||
value.children(self)
|
let AddrOf { mutable, expr } = a;
|
||||||
|
self.visit_mutability(mutable);
|
||||||
|
self.visit_expr_kind(expr);
|
||||||
}
|
}
|
||||||
fn visit_array(&mut self, value: &'a Array) {
|
fn visit_block(&mut self, b: &'a Block) {
|
||||||
value.children(self)
|
let Block { stmts } = b;
|
||||||
|
stmts.iter().for_each(|s| self.visit_stmt(s));
|
||||||
}
|
}
|
||||||
fn visit_array_rep(&mut self, value: &'a ArrayRep) {
|
fn visit_group(&mut self, g: &'a Group) {
|
||||||
value.children(self)
|
let Group { expr } = g;
|
||||||
|
self.visit_expr_kind(expr)
|
||||||
}
|
}
|
||||||
fn visit_addrof(&mut self, value: &'a AddrOf) {
|
fn visit_tuple(&mut self, t: &'a Tuple) {
|
||||||
value.children(self)
|
let Tuple { exprs } = t;
|
||||||
|
exprs.iter().for_each(|e| self.visit_expr(e))
|
||||||
}
|
}
|
||||||
fn visit_block(&mut self, value: &'a Block) {
|
fn visit_while(&mut self, w: &'a While) {
|
||||||
value.children(self)
|
let While { cond, pass, fail } = w;
|
||||||
|
self.visit_expr(cond);
|
||||||
|
self.visit_block(pass);
|
||||||
|
self.visit_else(fail);
|
||||||
}
|
}
|
||||||
fn visit_group(&mut self, value: &'a Group) {
|
fn visit_if(&mut self, i: &'a If) {
|
||||||
value.children(self)
|
let If { cond, pass, fail } = i;
|
||||||
|
self.visit_expr(cond);
|
||||||
|
self.visit_block(pass);
|
||||||
|
self.visit_else(fail);
|
||||||
}
|
}
|
||||||
fn visit_tuple(&mut self, value: &'a Tuple) {
|
fn visit_for(&mut self, f: &'a For) {
|
||||||
value.children(self)
|
let For { bind, cond, pass, fail } = f;
|
||||||
|
self.visit_sym(bind);
|
||||||
|
self.visit_expr(cond);
|
||||||
|
self.visit_block(pass);
|
||||||
|
self.visit_else(fail);
|
||||||
}
|
}
|
||||||
fn visit_while(&mut self, value: &'a While) {
|
fn visit_else(&mut self, e: &'a Else) {
|
||||||
value.children(self)
|
let Else { body } = e;
|
||||||
|
if let Some(body) = body {
|
||||||
|
self.visit_expr(body)
|
||||||
}
|
}
|
||||||
fn visit_if(&mut self, value: &'a If) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
}
|
||||||
fn visit_for(&mut self, value: &'a For) {
|
fn visit_break(&mut self, b: &'a Break) {
|
||||||
value.children(self)
|
let Break { body } = b;
|
||||||
|
if let Some(body) = body {
|
||||||
|
self.visit_expr(body)
|
||||||
}
|
}
|
||||||
fn visit_else(&mut self, value: &'a Else) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
}
|
||||||
fn visit_break(&mut self, value: &'a Break) {
|
fn visit_return(&mut self, r: &'a Return) {
|
||||||
value.children(self)
|
let Return { body } = r;
|
||||||
|
if let Some(body) = body {
|
||||||
|
self.visit_expr(body)
|
||||||
}
|
}
|
||||||
fn visit_return(&mut self, value: &'a Return) {
|
|
||||||
value.children(self)
|
|
||||||
}
|
}
|
||||||
fn visit_continue(&mut self) {}
|
fn visit_continue(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_literal<'a, V: Visit<'a>>(visitor: &mut V, l: &'a Literal) {
|
||||||
|
match l {
|
||||||
|
Literal::Bool(b) => visitor.visit_bool(b),
|
||||||
|
Literal::Char(c) => visitor.visit_char(c),
|
||||||
|
Literal::Int(i) => visitor.visit_int(i),
|
||||||
|
Literal::Float(f) => visitor.visit_smuggled_float(f),
|
||||||
|
Literal::String(s) => visitor.visit_string(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_meta_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a MetaKind) {
|
||||||
|
match kind {
|
||||||
|
MetaKind::Plain => {}
|
||||||
|
MetaKind::Equals(l) => visitor.visit_literal(l),
|
||||||
|
MetaKind::Func(lits) => lits.iter().for_each(|l| visitor.visit_literal(l)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_item_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a ItemKind) {
|
||||||
|
match kind {
|
||||||
|
ItemKind::Module(m) => visitor.visit_module(m),
|
||||||
|
ItemKind::Alias(a) => visitor.visit_alias(a),
|
||||||
|
ItemKind::Enum(e) => visitor.visit_enum(e),
|
||||||
|
ItemKind::Struct(s) => visitor.visit_struct(s),
|
||||||
|
ItemKind::Const(c) => visitor.visit_const(c),
|
||||||
|
ItemKind::Static(s) => visitor.visit_static(s),
|
||||||
|
ItemKind::Function(f) => visitor.visit_function(f),
|
||||||
|
ItemKind::Impl(i) => visitor.visit_impl(i),
|
||||||
|
ItemKind::Use(u) => visitor.visit_use(u),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_module_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a ModuleKind) {
|
||||||
|
match kind {
|
||||||
|
ModuleKind::Inline(f) => visitor.visit_file(f),
|
||||||
|
ModuleKind::Outline => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_struct_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a StructKind) {
|
||||||
|
match kind {
|
||||||
|
StructKind::Empty => {}
|
||||||
|
StructKind::Tuple(ty) => ty.iter().for_each(|t| visitor.visit_ty(t)),
|
||||||
|
StructKind::Struct(m) => m.iter().for_each(|m| visitor.visit_struct_member(m)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_enum_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a EnumKind) {
|
||||||
|
match kind {
|
||||||
|
EnumKind::NoVariants => {}
|
||||||
|
EnumKind::Variants(variants) => variants.iter().for_each(|v| visitor.visit_variant(v)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_variant_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a VariantKind) {
|
||||||
|
match kind {
|
||||||
|
VariantKind::Plain => {}
|
||||||
|
VariantKind::CLike(_) => {}
|
||||||
|
VariantKind::Tuple(t) => visitor.visit_ty(t),
|
||||||
|
VariantKind::Struct(m) => m.iter().for_each(|m| visitor.visit_struct_member(m)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_impl_kind<'a, V: Visit<'a>>(visitor: &mut V, target: &'a ImplKind) {
|
||||||
|
match target {
|
||||||
|
ImplKind::Type(t) => visitor.visit_ty(t),
|
||||||
|
ImplKind::Trait { impl_trait, for_type } => {
|
||||||
|
visitor.visit_path(impl_trait);
|
||||||
|
visitor.visit_ty(for_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_use_tree<'a, V: Visit<'a>>(visitor: &mut V, tree: &'a UseTree) {
|
||||||
|
match tree {
|
||||||
|
UseTree::Tree(tree) => {
|
||||||
|
tree.iter().for_each(|tree| visitor.visit_use_tree(tree));
|
||||||
|
}
|
||||||
|
UseTree::Path(path, rest) => {
|
||||||
|
visitor.visit_path_part(path);
|
||||||
|
visitor.visit_use_tree(rest)
|
||||||
|
}
|
||||||
|
UseTree::Alias(path, name) => {
|
||||||
|
visitor.visit_sym(path);
|
||||||
|
visitor.visit_sym(name);
|
||||||
|
}
|
||||||
|
UseTree::Name(name) => {
|
||||||
|
visitor.visit_sym(name);
|
||||||
|
}
|
||||||
|
UseTree::Glob => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_ty_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a TyKind) {
|
||||||
|
match kind {
|
||||||
|
TyKind::Never => {}
|
||||||
|
TyKind::Empty => {}
|
||||||
|
TyKind::Path(p) => visitor.visit_path(p),
|
||||||
|
TyKind::Array(t) => visitor.visit_ty_array(t),
|
||||||
|
TyKind::Slice(t) => visitor.visit_ty_slice(t),
|
||||||
|
TyKind::Tuple(t) => visitor.visit_ty_tuple(t),
|
||||||
|
TyKind::Ref(t) => visitor.visit_ty_ref(t),
|
||||||
|
TyKind::Fn(t) => visitor.visit_ty_fn(t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_stmt_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a StmtKind) {
|
||||||
|
match kind {
|
||||||
|
StmtKind::Empty => {}
|
||||||
|
StmtKind::Item(i) => visitor.visit_item(i),
|
||||||
|
StmtKind::Expr(e) => visitor.visit_expr(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or_visit_expr_kind<'a, V: Visit<'a>>(visitor: &mut V, e: &'a ExprKind) {
|
||||||
|
match e {
|
||||||
|
ExprKind::Empty => {}
|
||||||
|
ExprKind::Quote(_q) => {} // Quoted expressions are left unvisited
|
||||||
|
ExprKind::Let(l) => visitor.visit_let(l),
|
||||||
|
ExprKind::Match(m) => visitor.visit_match(m),
|
||||||
|
ExprKind::Assign(a) => visitor.visit_assign(a),
|
||||||
|
ExprKind::Modify(m) => visitor.visit_modify(m),
|
||||||
|
ExprKind::Binary(b) => visitor.visit_binary(b),
|
||||||
|
ExprKind::Unary(u) => visitor.visit_unary(u),
|
||||||
|
ExprKind::Cast(c) => visitor.visit_cast(c),
|
||||||
|
ExprKind::Member(m) => visitor.visit_member(m),
|
||||||
|
ExprKind::Index(i) => visitor.visit_index(i),
|
||||||
|
ExprKind::Structor(s) => visitor.visit_structor(s),
|
||||||
|
ExprKind::Path(p) => visitor.visit_path(p),
|
||||||
|
ExprKind::Literal(l) => visitor.visit_literal(l),
|
||||||
|
ExprKind::Array(a) => visitor.visit_array(a),
|
||||||
|
ExprKind::ArrayRep(a) => visitor.visit_array_rep(a),
|
||||||
|
ExprKind::AddrOf(a) => visitor.visit_addrof(a),
|
||||||
|
ExprKind::Block(b) => visitor.visit_block(b),
|
||||||
|
ExprKind::Group(g) => visitor.visit_group(g),
|
||||||
|
ExprKind::Tuple(t) => visitor.visit_tuple(t),
|
||||||
|
ExprKind::While(w) => visitor.visit_while(w),
|
||||||
|
ExprKind::If(i) => visitor.visit_if(i),
|
||||||
|
ExprKind::For(f) => visitor.visit_for(f),
|
||||||
|
ExprKind::Break(b) => visitor.visit_break(b),
|
||||||
|
ExprKind::Return(r) => visitor.visit_return(r),
|
||||||
|
ExprKind::Continue => visitor.visit_continue(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn or_visit_member_kind<'a, V: Visit<'a>>(visitor: &mut V, kind: &'a MemberKind) {
|
||||||
|
match kind {
|
||||||
|
MemberKind::Call(field, args) => {
|
||||||
|
visitor.visit_sym(field);
|
||||||
|
visitor.visit_tuple(args);
|
||||||
|
}
|
||||||
|
MemberKind::Struct(field) => visitor.visit_sym(field),
|
||||||
|
MemberKind::Tuple(field) => visitor.visit_literal(field),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,951 +0,0 @@
|
|||||||
//! Accepts an AST Visitor. Walks the AST, calling the visitor on each step.
|
|
||||||
|
|
||||||
use super::visit::Visit;
|
|
||||||
use crate::ast::*;
|
|
||||||
use cl_structures::span::Span;
|
|
||||||
|
|
||||||
/// Helps a [Visitor](Visit) walk through `Self`.
|
|
||||||
pub trait Walk {
|
|
||||||
/// Calls the respective `visit_*` function in V
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V);
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
/// Walks the children of self, visiting them in V
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for Span {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_span(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Sym {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_sym(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Mutability {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_mutability(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Visibility {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_visibility(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for bool {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_bool(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for char {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_char(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for u128 {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_int(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for u64 {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_smuggled_float(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for str {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_string(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Literal {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_literal(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
Literal::Bool(value) => value.children(v),
|
|
||||||
Literal::Char(value) => value.children(v),
|
|
||||||
Literal::Int(value) => value.children(v),
|
|
||||||
Literal::Float(value) => value.children(v),
|
|
||||||
Literal::String(value) => value.children(v),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for File {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_file(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let File { name: _, items } = self;
|
|
||||||
items.iter().for_each(|i| v.visit_item(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Attrs {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_attrs(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Attrs { meta } = self;
|
|
||||||
meta.children(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Meta {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_meta(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Meta { name, kind } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for MetaKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_meta_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
MetaKind::Plain => {}
|
|
||||||
MetaKind::Equals(lit) => lit.visit_in(v),
|
|
||||||
MetaKind::Func(lits) => lits.visit_in(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Item {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_item(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Item { span, attrs, vis, kind } = self;
|
|
||||||
span.visit_in(v);
|
|
||||||
attrs.visit_in(v);
|
|
||||||
vis.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for ItemKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_item_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
ItemKind::Module(value) => value.visit_in(v),
|
|
||||||
ItemKind::Alias(value) => value.visit_in(v),
|
|
||||||
ItemKind::Enum(value) => value.visit_in(v),
|
|
||||||
ItemKind::Struct(value) => value.visit_in(v),
|
|
||||||
ItemKind::Const(value) => value.visit_in(v),
|
|
||||||
ItemKind::Static(value) => value.visit_in(v),
|
|
||||||
ItemKind::Function(value) => value.visit_in(v),
|
|
||||||
ItemKind::Impl(value) => value.visit_in(v),
|
|
||||||
ItemKind::Use(value) => value.visit_in(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Generics {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_generics(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Self { vars } = self;
|
|
||||||
vars.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Module {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_module(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Module { name, file } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
file.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Alias {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_alias(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Alias { name, from } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
from.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Const {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_const(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Const { name, ty, init } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
ty.visit_in(v);
|
|
||||||
init.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Static {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_static(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Static { mutable, name, ty, init } = self;
|
|
||||||
mutable.visit_in(v);
|
|
||||||
name.visit_in(v);
|
|
||||||
ty.visit_in(v);
|
|
||||||
init.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Function {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_function(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Function { name, gens, sign, bind, body } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
gens.visit_in(v);
|
|
||||||
sign.visit_in(v);
|
|
||||||
bind.visit_in(v);
|
|
||||||
body.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Struct {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_struct(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Struct { name, gens, kind } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
gens.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for StructKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_struct_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
StructKind::Empty => {}
|
|
||||||
StructKind::Tuple(tys) => tys.visit_in(v),
|
|
||||||
StructKind::Struct(ms) => ms.visit_in(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for StructMember {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_struct_member(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let StructMember { vis, name, ty } = self;
|
|
||||||
vis.visit_in(v);
|
|
||||||
name.visit_in(v);
|
|
||||||
ty.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Enum {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_enum(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Enum { name, gens, variants } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
gens.visit_in(v);
|
|
||||||
variants.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Variant {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_variant(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Variant { name, kind, body } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
body.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Impl {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_impl(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Impl { target, body } = self;
|
|
||||||
target.visit_in(v);
|
|
||||||
body.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for ImplKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_impl_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
ImplKind::Type(t) => t.visit_in(v),
|
|
||||||
ImplKind::Trait { impl_trait, for_type } => {
|
|
||||||
impl_trait.visit_in(v);
|
|
||||||
for_type.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Use {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_use(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Use { absolute: _, tree } = self;
|
|
||||||
tree.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for UseTree {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_use_tree(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
UseTree::Tree(tree) => tree.iter().for_each(|t| t.visit_in(v)),
|
|
||||||
UseTree::Path(part, tree) => {
|
|
||||||
part.visit_in(v);
|
|
||||||
tree.visit_in(v);
|
|
||||||
}
|
|
||||||
UseTree::Alias(from, to) => {
|
|
||||||
from.visit_in(v);
|
|
||||||
to.visit_in(v);
|
|
||||||
}
|
|
||||||
UseTree::Name(name) => name.visit_in(v),
|
|
||||||
UseTree::Glob => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Ty {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_ty(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Ty { span, kind } = self;
|
|
||||||
span.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for TyKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_ty_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
TyKind::Never => {}
|
|
||||||
TyKind::Empty => {}
|
|
||||||
TyKind::Infer => {}
|
|
||||||
TyKind::Path(value) => value.visit_in(v),
|
|
||||||
TyKind::Array(value) => value.visit_in(v),
|
|
||||||
TyKind::Slice(value) => value.visit_in(v),
|
|
||||||
TyKind::Tuple(value) => value.visit_in(v),
|
|
||||||
TyKind::Ref(value) => value.visit_in(v),
|
|
||||||
TyKind::Fn(value) => value.visit_in(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for TyArray {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_ty_array(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let TyArray { ty, count: _ } = self;
|
|
||||||
ty.visit_in(v);
|
|
||||||
// count.walk(v); // not available
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for TySlice {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_ty_slice(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let TySlice { ty } = self;
|
|
||||||
ty.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for TyTuple {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_ty_tuple(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let TyTuple { types } = self;
|
|
||||||
types.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for TyRef {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_ty_ref(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let TyRef { mutable, count: _, to } = self;
|
|
||||||
mutable.children(v);
|
|
||||||
to.children(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for TyFn {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_ty_fn(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let TyFn { args, rety } = self;
|
|
||||||
args.visit_in(v);
|
|
||||||
rety.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Path {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_path(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Path { absolute: _, parts } = self;
|
|
||||||
parts.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for PathPart {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_path_part(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
PathPart::SuperKw => {}
|
|
||||||
PathPart::SelfTy => {}
|
|
||||||
PathPart::Ident(sym) => sym.visit_in(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Stmt {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_stmt(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Stmt { span, kind, semi } = self;
|
|
||||||
span.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
semi.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for StmtKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_stmt_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
StmtKind::Empty => {}
|
|
||||||
StmtKind::Item(value) => value.visit_in(v),
|
|
||||||
StmtKind::Expr(value) => value.visit_in(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Semi {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_semi(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Expr {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_expr(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Expr { span, kind } = self;
|
|
||||||
span.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for ExprKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_expr_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
ExprKind::Empty => {}
|
|
||||||
ExprKind::Closure(value) => value.visit_in(v),
|
|
||||||
ExprKind::Tuple(value) => value.visit_in(v),
|
|
||||||
ExprKind::Structor(value) => value.visit_in(v),
|
|
||||||
ExprKind::Array(value) => value.visit_in(v),
|
|
||||||
ExprKind::ArrayRep(value) => value.visit_in(v),
|
|
||||||
ExprKind::AddrOf(value) => value.visit_in(v),
|
|
||||||
ExprKind::Quote(value) => value.visit_in(v),
|
|
||||||
ExprKind::Literal(value) => value.visit_in(v),
|
|
||||||
ExprKind::Group(value) => value.visit_in(v),
|
|
||||||
ExprKind::Block(value) => value.visit_in(v),
|
|
||||||
ExprKind::Assign(value) => value.visit_in(v),
|
|
||||||
ExprKind::Modify(value) => value.visit_in(v),
|
|
||||||
ExprKind::Binary(value) => value.visit_in(v),
|
|
||||||
ExprKind::Unary(value) => value.visit_in(v),
|
|
||||||
ExprKind::Member(value) => value.visit_in(v),
|
|
||||||
ExprKind::Index(value) => value.visit_in(v),
|
|
||||||
ExprKind::Cast(value) => value.visit_in(v),
|
|
||||||
ExprKind::Path(value) => value.visit_in(v),
|
|
||||||
ExprKind::Let(value) => value.visit_in(v),
|
|
||||||
ExprKind::Match(value) => value.visit_in(v),
|
|
||||||
ExprKind::While(value) => value.visit_in(v),
|
|
||||||
ExprKind::If(value) => value.visit_in(v),
|
|
||||||
ExprKind::For(value) => value.visit_in(v),
|
|
||||||
ExprKind::Break(value) => value.visit_in(v),
|
|
||||||
ExprKind::Return(value) => value.visit_in(v),
|
|
||||||
ExprKind::Continue => v.visit_continue(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for Closure {
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_closure(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Self { arg, body } = self;
|
|
||||||
v.visit_pattern(arg);
|
|
||||||
v.visit_expr(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walk for Tuple {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_tuple(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Tuple { exprs } = self;
|
|
||||||
exprs.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Structor {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_structor(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Structor { to, init } = self;
|
|
||||||
to.visit_in(v);
|
|
||||||
init.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Fielder {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_fielder(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Fielder { name, init } = self;
|
|
||||||
name.visit_in(v);
|
|
||||||
init.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Array {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_array(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Array { values } = self;
|
|
||||||
values.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for ArrayRep {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_array_rep(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let ArrayRep { value, repeat: _ } = self;
|
|
||||||
value.visit_in(v);
|
|
||||||
// repeat.visit_in(v) // TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for AddrOf {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_addrof(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let AddrOf { mutable, expr } = self;
|
|
||||||
mutable.visit_in(v);
|
|
||||||
expr.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Cast {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_cast(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Cast { head, ty } = self;
|
|
||||||
head.visit_in(v);
|
|
||||||
ty.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Quote {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_quote(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Quote { quote } = self;
|
|
||||||
quote.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Group {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_group(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Group { expr } = self;
|
|
||||||
expr.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Block {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_block(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Block { stmts } = self;
|
|
||||||
stmts.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Assign {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_assign(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Assign { parts } = self;
|
|
||||||
parts.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Modify {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_modify(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Modify { kind, parts } = self;
|
|
||||||
kind.visit_in(v);
|
|
||||||
parts.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for ModifyKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_modify_kind(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Binary {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_binary(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Binary { kind, parts } = self;
|
|
||||||
kind.visit_in(v);
|
|
||||||
parts.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for BinaryKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_binary_kind(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Unary {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_unary(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Unary { kind, tail } = self;
|
|
||||||
kind.visit_in(v);
|
|
||||||
tail.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for UnaryKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_unary_kind(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Member {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_member(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Member { head, kind } = self;
|
|
||||||
head.visit_in(v);
|
|
||||||
kind.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for MemberKind {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_member_kind(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
MemberKind::Call(sym, tuple) => {
|
|
||||||
sym.visit_in(v);
|
|
||||||
tuple.visit_in(v);
|
|
||||||
}
|
|
||||||
MemberKind::Struct(sym) => sym.visit_in(v),
|
|
||||||
MemberKind::Tuple(literal) => literal.visit_in(v),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Index {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_index(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Index { head, indices } = self;
|
|
||||||
head.visit_in(v);
|
|
||||||
indices.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Let {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_let(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Let { mutable, name, ty, init } = self;
|
|
||||||
mutable.visit_in(v);
|
|
||||||
name.visit_in(v);
|
|
||||||
ty.visit_in(v);
|
|
||||||
init.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Match {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_match(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Match { scrutinee, arms } = self;
|
|
||||||
scrutinee.visit_in(v);
|
|
||||||
arms.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for MatchArm {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_match_arm(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let MatchArm(pat, expr) = self;
|
|
||||||
pat.visit_in(v);
|
|
||||||
expr.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Pattern {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_pattern(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
match self {
|
|
||||||
Pattern::Name(sym) => sym.visit_in(v),
|
|
||||||
Pattern::Path(path) => path.visit_in(v),
|
|
||||||
Pattern::Literal(literal) => literal.visit_in(v),
|
|
||||||
Pattern::Rest(pattern) => pattern.visit_in(v),
|
|
||||||
Pattern::Ref(mutability, pattern) => {
|
|
||||||
mutability.visit_in(v);
|
|
||||||
pattern.visit_in(v);
|
|
||||||
}
|
|
||||||
Pattern::RangeExc(from, to) => {
|
|
||||||
from.visit_in(v);
|
|
||||||
to.visit_in(v);
|
|
||||||
}
|
|
||||||
Pattern::RangeInc(from, to) => {
|
|
||||||
from.visit_in(v);
|
|
||||||
to.visit_in(v);
|
|
||||||
}
|
|
||||||
Pattern::Tuple(patterns) => patterns.visit_in(v),
|
|
||||||
Pattern::Array(patterns) => patterns.visit_in(v),
|
|
||||||
Pattern::Struct(path, items) => {
|
|
||||||
path.visit_in(v);
|
|
||||||
items.visit_in(v);
|
|
||||||
}
|
|
||||||
Pattern::TupleStruct(path, patterns) => {
|
|
||||||
path.visit_in(v);
|
|
||||||
patterns.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for While {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_while(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let While { cond, pass, fail } = self;
|
|
||||||
cond.visit_in(v);
|
|
||||||
pass.visit_in(v);
|
|
||||||
fail.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for If {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_if(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let If { cond, pass, fail } = self;
|
|
||||||
cond.visit_in(v);
|
|
||||||
pass.visit_in(v);
|
|
||||||
fail.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for For {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_for(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let For { bind, cond, pass, fail } = self;
|
|
||||||
bind.visit_in(v);
|
|
||||||
cond.visit_in(v);
|
|
||||||
pass.visit_in(v);
|
|
||||||
fail.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Else {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_else(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Else { body } = self;
|
|
||||||
body.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Break {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_break(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Break { body } = self;
|
|
||||||
body.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Walk for Return {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
v.visit_return(self);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let Return { body } = self;
|
|
||||||
body.visit_in(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- BLANKET IMPLEMENTATIONS
|
|
||||||
|
|
||||||
impl<T: Walk> Walk for [T] {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
self.iter().for_each(|value| value.visit_in(v));
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
self.iter().for_each(|value| value.children(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Walk> Walk for Vec<T> {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
self.as_slice().visit_in(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
self.as_slice().children(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Walk, B: Walk> Walk for (A, B) {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let (a, b) = self;
|
|
||||||
a.visit_in(v);
|
|
||||||
b.visit_in(v);
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
let (a, b) = self;
|
|
||||||
a.children(v);
|
|
||||||
b.children(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Walk> Walk for Option<T> {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
if let Some(value) = self.as_ref() {
|
|
||||||
value.visit_in(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
if let Some(value) = self {
|
|
||||||
value.children(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Walk> Walk for Box<T> {
|
|
||||||
#[inline]
|
|
||||||
fn visit_in<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
self.as_ref().visit_in(v)
|
|
||||||
}
|
|
||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
|
||||||
self.as_ref().children(v)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,9 @@
|
|||||||
//! Desugaring passes for Conlang
|
//! Desugaring passes for Conlang
|
||||||
|
|
||||||
pub mod constant_folder;
|
|
||||||
pub mod path_absoluter;
|
pub mod path_absoluter;
|
||||||
pub mod squash_groups;
|
pub mod squash_groups;
|
||||||
pub mod while_else;
|
pub mod while_else;
|
||||||
|
|
||||||
pub use constant_folder::ConstantFolder;
|
|
||||||
pub use path_absoluter::NormalizePaths;
|
pub use path_absoluter::NormalizePaths;
|
||||||
pub use squash_groups::SquashGroups;
|
pub use squash_groups::SquashGroups;
|
||||||
pub use while_else::WhileElseDesugar;
|
pub use while_else::WhileElseDesugar;
|
||||||
|
@ -1,89 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
ast::{ExprKind as Ek, *},
|
|
||||||
ast_visitor::{Fold, fold::or_fold_expr_kind},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct ConstantFolder;
|
|
||||||
|
|
||||||
macro bin_rule(
|
|
||||||
match ($kind: ident, $head: expr, $tail: expr) {
|
|
||||||
$(($op:ident, $impl:expr, $($ty:ident -> $rety:ident),*)),*$(,)?
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
#[allow(clippy::all)]
|
|
||||||
match ($kind, $head, $tail) {
|
|
||||||
$($(( BinaryKind::$op,
|
|
||||||
Expr { kind: ExprKind::Literal(Literal::$ty(a)), .. },
|
|
||||||
Expr { kind: ExprKind::Literal(Literal::$ty(b)), .. },
|
|
||||||
) => {
|
|
||||||
ExprKind::Literal(Literal::$rety($impl(a, b)))
|
|
||||||
},)*)*
|
|
||||||
(kind, head, tail) => ExprKind::Binary(Binary {
|
|
||||||
kind,
|
|
||||||
parts: Box::new((head, tail)),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro un_rule(
|
|
||||||
match ($kind: ident, $tail: expr) {
|
|
||||||
$(($op:ident, $impl:expr, $($ty:ident),*)),*$(,)?
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
match ($kind, $tail) {
|
|
||||||
$($((UnaryKind::$op, Expr { kind: ExprKind::Literal(Literal::$ty(v)), .. }) => {
|
|
||||||
ExprKind::Literal(Literal::$ty($impl(v)))
|
|
||||||
},)*)*
|
|
||||||
(kind, tail) => ExprKind::Unary(Unary { kind, tail: Box::new(tail) }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fold for ConstantFolder {
|
|
||||||
fn fold_expr_kind(&mut self, kind: Ek) -> Ek {
|
|
||||||
match kind {
|
|
||||||
Ek::Group(Group { expr }) => self.fold_expr_kind(expr.kind),
|
|
||||||
Ek::Binary(Binary { kind, parts }) => {
|
|
||||||
let (head, tail) = *parts;
|
|
||||||
bin_rule! (match (kind, self.fold_expr(head), self.fold_expr(tail)) {
|
|
||||||
(Lt, |a, b| a < b, Bool -> Bool, Int -> Bool),
|
|
||||||
(LtEq, |a, b| a <= b, Bool -> Bool, Int -> Bool),
|
|
||||||
(Equal, |a, b| a == b, Bool -> Bool, Int -> Bool),
|
|
||||||
(NotEq, |a, b| a != b, Bool -> Bool, Int -> Bool),
|
|
||||||
(GtEq, |a, b| a >= b, Bool -> Bool, Int -> Bool),
|
|
||||||
(Gt, |a, b| a > b, Bool -> Bool, Int -> Bool),
|
|
||||||
(BitAnd, |a, b| a & b, Bool -> Bool, Int -> Int),
|
|
||||||
(BitOr, |a, b| a | b, Bool -> Bool, Int -> Int),
|
|
||||||
(BitXor, |a, b| a ^ b, Bool -> Bool, Int -> Int),
|
|
||||||
(Shl, |a, b| a << b, Int -> Int),
|
|
||||||
(Shr, |a, b| a >> b, Int -> Int),
|
|
||||||
(Add, |a, b| a + b, Int -> Int),
|
|
||||||
(Sub, |a, b| a - b, Int -> Int),
|
|
||||||
(Mul, |a, b| a * b, Int -> Int),
|
|
||||||
(Div, |a, b| a / b, Int -> Int),
|
|
||||||
(Rem, |a, b| a % b, Int -> Int),
|
|
||||||
// Cursed bit-smuggled float shenanigans
|
|
||||||
(Lt, |a, b| (f64::from_bits(a) < f64::from_bits(b)), Float -> Bool),
|
|
||||||
(LtEq, |a, b| (f64::from_bits(a) >= f64::from_bits(b)), Float -> Bool),
|
|
||||||
(Equal, |a, b| (f64::from_bits(a) == f64::from_bits(b)), Float -> Bool),
|
|
||||||
(NotEq, |a, b| (f64::from_bits(a) != f64::from_bits(b)), Float -> Bool),
|
|
||||||
(GtEq, |a, b| (f64::from_bits(a) <= f64::from_bits(b)), Float -> Bool),
|
|
||||||
(Gt, |a, b| (f64::from_bits(a) > f64::from_bits(b)), Float -> Bool),
|
|
||||||
(Add, |a, b| (f64::from_bits(a) + f64::from_bits(b)).to_bits(), Float -> Float),
|
|
||||||
(Sub, |a, b| (f64::from_bits(a) - f64::from_bits(b)).to_bits(), Float -> Float),
|
|
||||||
(Mul, |a, b| (f64::from_bits(a) * f64::from_bits(b)).to_bits(), Float -> Float),
|
|
||||||
(Div, |a, b| (f64::from_bits(a) / f64::from_bits(b)).to_bits(), Float -> Float),
|
|
||||||
(Rem, |a, b| (f64::from_bits(a) % f64::from_bits(b)).to_bits(), Float -> Float),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Ek::Unary(Unary { kind, tail }) => {
|
|
||||||
un_rule! (match (kind, self.fold_expr(*tail)) {
|
|
||||||
(Not, std::ops::Not::not, Int, Bool),
|
|
||||||
(Neg, std::ops::Not::not, Int, Bool),
|
|
||||||
(Neg, |f| (-f64::from_bits(f)).to_bits(), Float),
|
|
||||||
(At, std::ops::Not::not, Float), /* Lmao */
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => or_fold_expr_kind(self, kind),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,14 +23,13 @@ impl Default for NormalizePaths {
|
|||||||
|
|
||||||
impl Fold for NormalizePaths {
|
impl Fold for NormalizePaths {
|
||||||
fn fold_module(&mut self, m: Module) -> Module {
|
fn fold_module(&mut self, m: Module) -> Module {
|
||||||
let Module { name, file } = m;
|
let Module { name, kind } = m;
|
||||||
self.path.push(PathPart::Ident(name));
|
self.path.push(PathPart::Ident(name));
|
||||||
|
|
||||||
let name = self.fold_sym(name);
|
let (name, kind) = (self.fold_sym(name), self.fold_module_kind(kind));
|
||||||
let file = file.map(|f| self.fold_file(f));
|
|
||||||
|
|
||||||
self.path.pop();
|
self.path.pop();
|
||||||
Module { name, file }
|
Module { name, kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_path(&mut self, p: Path) -> Path {
|
fn fold_path(&mut self, p: Path) -> Path {
|
||||||
|
@ -7,7 +7,7 @@ pub struct SquashGroups;
|
|||||||
impl Fold for SquashGroups {
|
impl Fold for SquashGroups {
|
||||||
fn fold_expr_kind(&mut self, kind: ExprKind) -> ExprKind {
|
fn fold_expr_kind(&mut self, kind: ExprKind) -> ExprKind {
|
||||||
match kind {
|
match kind {
|
||||||
ExprKind::Group(Group { expr }) => self.fold_expr(*expr).kind,
|
ExprKind::Group(Group { expr }) => self.fold_expr_kind(*expr),
|
||||||
_ => or_fold_expr_kind(self, kind),
|
_ => or_fold_expr_kind(self, kind),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,27 +10,24 @@ pub struct WhileElseDesugar;
|
|||||||
|
|
||||||
impl Fold for WhileElseDesugar {
|
impl Fold for WhileElseDesugar {
|
||||||
fn fold_expr(&mut self, e: Expr) -> Expr {
|
fn fold_expr(&mut self, e: Expr) -> Expr {
|
||||||
let Expr { span, kind } = e;
|
let Expr { extents, kind } = e;
|
||||||
let kind = desugar_while(span, kind);
|
let kind = desugar_while(extents, kind);
|
||||||
Expr { span: self.fold_span(span), kind: self.fold_expr_kind(kind) }
|
Expr { extents: self.fold_span(extents), kind: self.fold_expr_kind(kind) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Desugars while(-else) expressions into loop-if-else-break expressions
|
/// Desugars while(-else) expressions into loop-if-else-break expressions
|
||||||
fn desugar_while(span: Span, kind: ExprKind) -> ExprKind {
|
fn desugar_while(extents: Span, kind: ExprKind) -> ExprKind {
|
||||||
match kind {
|
match kind {
|
||||||
// work backwards: fail -> break -> if -> loop
|
// work backwards: fail -> break -> if -> loop
|
||||||
ExprKind::While(While { cond, pass, fail: Else { body } }) => {
|
ExprKind::While(While { cond, pass, fail: Else { body } }) => {
|
||||||
// Preserve the else-expression's span, if present, or use the parent's span
|
// Preserve the else-expression's extents, if present, or use the parent's extents
|
||||||
let fail_span = body.as_ref().map(|body| body.span).unwrap_or(span);
|
let fail_span = body.as_ref().map(|body| body.extents).unwrap_or(extents);
|
||||||
let break_expr = Expr { span: fail_span, kind: ExprKind::Break(Break { body }) };
|
let break_expr = Expr { extents: fail_span, kind: ExprKind::Break(Break { body }) };
|
||||||
|
|
||||||
let loop_body = If { cond, pass, fail: Else { body: Some(Box::new(break_expr)) } };
|
let loop_body = If { cond, pass, fail: Else { body: Some(Box::new(break_expr)) } };
|
||||||
let loop_body = ExprKind::If(loop_body);
|
let loop_body = ExprKind::If(loop_body);
|
||||||
ExprKind::Unary(Unary {
|
ExprKind::Unary(Unary { kind: UnaryKind::Loop, tail: Box::new(loop_body) })
|
||||||
kind: UnaryKind::Loop,
|
|
||||||
tail: Box::new(Expr { span, kind: loop_body }),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_ => kind,
|
_ => kind,
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
|
|
||||||
pub use ast::*;
|
pub use ast::*;
|
||||||
pub use ast_impl::weight_of::WeightOf;
|
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod ast_impl;
|
pub mod ast_impl;
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "cl-embed"
|
|
||||||
version = "0.1.0"
|
|
||||||
repository.workspace = true
|
|
||||||
authors.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
license.workspace = true
|
|
||||||
publish.workspace = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
cl-interpret = { path = "../cl-interpret" }
|
|
||||||
cl-ast = { path = "../cl-ast" }
|
|
||||||
cl-structures = { path = "../cl-structures" }
|
|
||||||
cl-lexer = { path = "../cl-lexer" }
|
|
||||||
cl-parser = { path = "../cl-parser" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
repline = { path = "../../repline" }
|
|
@ -1,25 +0,0 @@
|
|||||||
use cl_embed::*;
|
|
||||||
use repline::{Response, prebaked};
|
|
||||||
|
|
||||||
fn main() -> Result<(), repline::Error> {
|
|
||||||
prebaked::read_and("", "calc >", " ? >", |line| {
|
|
||||||
calc(line).map_err(Into::into)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calc(line: &str) -> Result<Response, EvalError> {
|
|
||||||
let mut env = Environment::new();
|
|
||||||
env.bind("line", line);
|
|
||||||
|
|
||||||
let res = conlang!(
|
|
||||||
mod expression;
|
|
||||||
use expression::{eval, parse};
|
|
||||||
|
|
||||||
let (expr, rest) = parse(line.chars(), 0);
|
|
||||||
eval(expr)
|
|
||||||
)(&mut env)?;
|
|
||||||
|
|
||||||
println!("{res}");
|
|
||||||
|
|
||||||
Ok(Response::Accept)
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
../../../../sample-code/calculator.cl
|
|
@ -1,126 +0,0 @@
|
|||||||
//! Embed Conlang code into your Rust project!
|
|
||||||
//!
|
|
||||||
//! # This crate is experimental, and has no guarantees of stability.
|
|
||||||
#![feature(decl_macro)]
|
|
||||||
#![cfg_attr(test, feature(assert_matches))]
|
|
||||||
#![allow(unused_imports)]
|
|
||||||
|
|
||||||
pub use cl_interpret::{convalue::ConValue as Value, env::Environment};
|
|
||||||
|
|
||||||
use cl_ast::{Block, Module, ast_visitor::Fold};
|
|
||||||
use cl_interpret::{convalue::ConValue, interpret::Interpret};
|
|
||||||
use cl_lexer::Lexer;
|
|
||||||
use cl_parser::{Parser, error::Error as ParseError, inliner::ModuleInliner};
|
|
||||||
use std::{path::Path, sync::OnceLock};
|
|
||||||
|
|
||||||
/// Constructs a function which evaluates a Conlang Block
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Bind and use a variable
|
|
||||||
/// ```rust
|
|
||||||
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
/// use cl_embed::{conlang, Environment, Value};
|
|
||||||
///
|
|
||||||
/// let mut env = Environment::new();
|
|
||||||
///
|
|
||||||
/// // Bind a variable named `message` to "Hello, world!"
|
|
||||||
/// env.bind("message", "Hello, World!");
|
|
||||||
///
|
|
||||||
/// let print_hello = conlang!{
|
|
||||||
/// println(message);
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// // Run the function
|
|
||||||
/// let ret = print_hello(&mut env)?;
|
|
||||||
///
|
|
||||||
/// // `println` returns Empty
|
|
||||||
/// assert!(matches!(ret, Value::Empty));
|
|
||||||
///
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub macro conlang (
|
|
||||||
$($t:tt)*
|
|
||||||
) {{
|
|
||||||
// Parse once
|
|
||||||
static FN: OnceLock<Result<Block, ParseError>> = OnceLock::new();
|
|
||||||
|
|
||||||
|env: &mut Environment| -> Result<ConValue, EvalError> {
|
|
||||||
FN.get_or_init(|| {
|
|
||||||
// TODO: embed the full module tree at compile time
|
|
||||||
let path = AsRef::<Path>::as_ref(&concat!(env!("CARGO_MANIFEST_DIR"),"/../../", file!())).with_extension("");
|
|
||||||
let mut mi = ModuleInliner::new(path);
|
|
||||||
let code = mi.fold_block(
|
|
||||||
Parser::new(
|
|
||||||
concat!(file!(), ":", line!(), ":"),
|
|
||||||
Lexer::new(stringify!({ $($t)* })),
|
|
||||||
)
|
|
||||||
.parse::<Block>()?,
|
|
||||||
);
|
|
||||||
if let Some((ie, pe)) = mi.into_errs() {
|
|
||||||
for (file, err) in ie {
|
|
||||||
eprintln!("{}: {err}", file.display());
|
|
||||||
}
|
|
||||||
for (file, err) in pe {
|
|
||||||
eprintln!("{}: {err}", file.display());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(code)
|
|
||||||
})
|
|
||||||
.as_ref()
|
|
||||||
.map_err(Clone::clone)?
|
|
||||||
.interpret(env)
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum EvalError {
|
|
||||||
Parse(cl_parser::error::Error),
|
|
||||||
Interpret(cl_interpret::error::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<cl_parser::error::Error> for EvalError {
|
|
||||||
fn from(value: cl_parser::error::Error) -> Self {
|
|
||||||
Self::Parse(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<cl_interpret::error::Error> for EvalError {
|
|
||||||
fn from(value: cl_interpret::error::Error) -> Self {
|
|
||||||
Self::Interpret(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::error::Error for EvalError {}
|
|
||||||
impl std::fmt::Display for EvalError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
EvalError::Parse(error) => error.fmt(f),
|
|
||||||
EvalError::Interpret(error) => error.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use std::assert_matches::assert_matches;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_works() -> Result<(), EvalError> {
|
|
||||||
let mut env = Environment::new();
|
|
||||||
|
|
||||||
let result = conlang! {
|
|
||||||
fn add(left, right) -> isize {
|
|
||||||
left + right
|
|
||||||
}
|
|
||||||
|
|
||||||
add(2, 2)
|
|
||||||
}(&mut env);
|
|
||||||
|
|
||||||
assert_matches!(result, Ok(Value::Int(4)));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let parent = path.parent().unwrap_or("".as_ref());
|
let parent = path.parent().unwrap_or("".as_ref());
|
||||||
|
|
||||||
let code = std::fs::read_to_string(&path)?;
|
let code = std::fs::read_to_string(&path)?;
|
||||||
let code = Parser::new(path.display().to_string(), Lexer::new(&code)).parse()?;
|
let code = Parser::new(Lexer::new(&code)).parse()?;
|
||||||
let code = match ModuleInliner::new(parent).inline(code) {
|
let code = match ModuleInliner::new(parent).inline(code) {
|
||||||
Ok(code) => code,
|
Ok(code) => code,
|
||||||
Err((code, ioerrs, perrs)) => {
|
Err((code, ioerrs, perrs)) => {
|
||||||
@ -40,7 +40,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
if env.get(main).is_ok() {
|
if env.get(main).is_ok() {
|
||||||
let args = args
|
let args = args
|
||||||
.flat_map(|arg| {
|
.flat_map(|arg| {
|
||||||
Parser::new(&arg, Lexer::new(&arg))
|
Parser::new(Lexer::new(&arg))
|
||||||
.parse::<Expr>()
|
.parse::<Expr>()
|
||||||
.map(|arg| env.eval(&arg))
|
.map(|arg| env.eval(&arg))
|
||||||
})
|
})
|
||||||
|
@ -5,7 +5,10 @@ use crate::{
|
|||||||
env::Environment,
|
env::Environment,
|
||||||
error::{Error, IResult},
|
error::{Error, IResult},
|
||||||
};
|
};
|
||||||
use std::io::{Write, stdout};
|
use std::{
|
||||||
|
io::{stdout, Write},
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
|
||||||
/// A function built into the interpreter.
|
/// A function built into the interpreter.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -54,7 +57,7 @@ impl super::Callable for Builtin {
|
|||||||
/// Turns a function definition into a [Builtin].
|
/// Turns a function definition into a [Builtin].
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use cl_interpret::{builtin::builtin, convalue::ConValue};
|
/// # use cl_interpret::{builtin2::builtin, convalue::ConValue};
|
||||||
/// let my_builtin = builtin! {
|
/// let my_builtin = builtin! {
|
||||||
/// /// Use the `@env` suffix to bind the environment!
|
/// /// Use the `@env` suffix to bind the environment!
|
||||||
/// /// (needed for recursive calls)
|
/// /// (needed for recursive calls)
|
||||||
@ -75,11 +78,11 @@ pub macro builtin(
|
|||||||
$(#[$($meta)*])*
|
$(#[$($meta)*])*
|
||||||
fn $name(_env: &mut Environment, _args: &[ConValue]) -> IResult<ConValue> {
|
fn $name(_env: &mut Environment, _args: &[ConValue]) -> IResult<ConValue> {
|
||||||
// Set up the builtin! environment
|
// Set up the builtin! environment
|
||||||
$(#[allow(unused)]let $env = _env;)?
|
$(let $env = _env;)?
|
||||||
// Allow for single argument `fn foo(args @ ..)` pattern
|
// Allow for single argument `fn foo(args @ ..)` pattern
|
||||||
#[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
|
#[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
|
||||||
let [$($arg),*] = _args else {
|
let [$($arg),*] = _args else {
|
||||||
Err($crate::error::Error::TypeError())?
|
Err($crate::error::Error::TypeError)?
|
||||||
};
|
};
|
||||||
$body.map(Into::into)
|
$body.map(Into::into)
|
||||||
}
|
}
|
||||||
@ -98,10 +101,10 @@ pub macro builtins($(
|
|||||||
[$(builtin!($(#[$($meta)*])* fn $name ($($args)*) $(@$env)? $body)),*]
|
[$(builtin!($(#[$($meta)*])* fn $name ($($args)*) $(@$env)? $body)),*]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [Error::BuiltinError] using interpolation of runtime expressions.
|
/// Creates an [Error::BuiltinDebug] using interpolation of runtime expressions.
|
||||||
/// See [std::format].
|
/// See [std::format].
|
||||||
pub macro error_format ($($t:tt)*) {
|
pub macro error_format ($($t:tt)*) {
|
||||||
$crate::error::Error::BuiltinError(format!($($t)*))
|
$crate::error::Error::BuiltinDebug(format!($($t)*))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Builtins: &[Builtin] = &builtins![
|
pub const Builtins: &[Builtin] = &builtins![
|
||||||
@ -143,11 +146,6 @@ pub const Builtins: &[Builtin] = &builtins![
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn panic(message) {
|
|
||||||
Err(error_format!("Panic: {message}"))?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Dumps the environment
|
/// Dumps the environment
|
||||||
fn dump() @env {
|
fn dump() @env {
|
||||||
println!("{env}");
|
println!("{env}");
|
||||||
@ -155,8 +153,8 @@ pub const Builtins: &[Builtin] = &builtins![
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn builtins() @env {
|
fn builtins() @env {
|
||||||
for builtin in env.globals().values().flatten().filter(|v| matches!(v, ConValue::Builtin(_))) {
|
for builtin in env.builtins().values().flatten() {
|
||||||
println!("{builtin}")
|
println!("{builtin}");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -166,22 +164,12 @@ pub const Builtins: &[Builtin] = &builtins![
|
|||||||
Ok(match list {
|
Ok(match list {
|
||||||
ConValue::Empty => 0,
|
ConValue::Empty => 0,
|
||||||
ConValue::String(s) => s.chars().count() as _,
|
ConValue::String(s) => s.chars().count() as _,
|
||||||
ConValue::Ref(r) => {
|
ConValue::Ref(r) => return len(env, slice::from_ref(r.as_ref())),
|
||||||
return len(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
|
|
||||||
}
|
|
||||||
ConValue::Array(t) => t.len() as _,
|
ConValue::Array(t) => t.len() as _,
|
||||||
ConValue::Tuple(t) => t.len() as _,
|
ConValue::Tuple(t) => t.len() as _,
|
||||||
_ => Err(Error::TypeError())?,
|
ConValue::RangeExc(start, end) => (end - start) as _,
|
||||||
})
|
ConValue::RangeInc(start, end) => (end - start + 1) as _,
|
||||||
}
|
_ => Err(Error::TypeError)?,
|
||||||
|
|
||||||
fn chars(string) @env {
|
|
||||||
Ok(match string {
|
|
||||||
ConValue::String(s) => ConValue::Array(s.chars().map(Into::into).collect()),
|
|
||||||
ConValue::Ref(r) => {
|
|
||||||
return chars(env, &[env.get_id(*r).ok_or(Error::StackOverflow(*r))?.clone()])
|
|
||||||
}
|
|
||||||
_ => Err(Error::TypeError())?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,10 +178,6 @@ pub const Builtins: &[Builtin] = &builtins![
|
|||||||
Ok(ConValue::Empty)
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slice_of(ConValue::Ref(arr), ConValue::Int(start)) {
|
|
||||||
Ok(ConValue::Slice(*arr, *start as usize))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a shark
|
/// Returns a shark
|
||||||
fn shark() {
|
fn shark() {
|
||||||
Ok('\u{1f988}')
|
Ok('\u{1f988}')
|
||||||
@ -206,7 +190,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a * b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a * b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +199,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
Ok(match (lhs, rhs){
|
Ok(match (lhs, rhs){
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a / b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a / b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +208,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a % b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a % b),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +218,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
|
||||||
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
|
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +227,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a - b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a - b),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +236,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a << b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a << b),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +245,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a >> b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a >> b),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +255,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +265,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,29 +275,24 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
/// Exclusive Range `a..b`
|
||||||
fn RangeExc(start, end) {
|
fn range_exc(from, to) {
|
||||||
Ok(ConValue::TupleStruct(Box::new((
|
let (&ConValue::Int(from), &ConValue::Int(to)) = (from, to) else {
|
||||||
"RangeExc", Box::new([start.clone(), end.clone()])
|
Err(Error::TypeError)?
|
||||||
))))
|
};
|
||||||
|
Ok(ConValue::RangeExc(from, to))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
/// Inclusive Range `a..=b`
|
||||||
fn RangeInc(start, end) {
|
fn range_inc(from, to) {
|
||||||
Ok(ConValue::TupleStruct(Box::new((
|
let (&ConValue::Int(from), &ConValue::Int(to)) = (from, to) else {
|
||||||
"RangeInc", Box::new([start.clone(), end.clone()])
|
Err(Error::TypeError)?
|
||||||
))))
|
};
|
||||||
}
|
Ok(ConValue::RangeInc(from, to))
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn RangeTo(end) {
|
|
||||||
Ok(ConValue::TupleStruct(Box::new((
|
|
||||||
"RangeInc", Box::new([end.clone()])
|
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Negates the ConValue
|
/// Negates the ConValue
|
||||||
@ -322,7 +301,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
ConValue::Empty => ConValue::Empty,
|
ConValue::Empty => ConValue::Empty,
|
||||||
ConValue::Int(v) => ConValue::Int(v.wrapping_neg()),
|
ConValue::Int(v) => ConValue::Int(v.wrapping_neg()),
|
||||||
ConValue::Float(v) => ConValue::Float(-v),
|
ConValue::Float(v) => ConValue::Float(-v),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +311,7 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
ConValue::Empty => ConValue::Empty,
|
ConValue::Empty => ConValue::Empty,
|
||||||
ConValue::Int(v) => ConValue::Int(!v),
|
ConValue::Int(v) => ConValue::Int(!v),
|
||||||
ConValue::Bool(v) => ConValue::Bool(!v),
|
ConValue::Bool(v) => ConValue::Bool(!v),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,9 +327,10 @@ pub const Math: &[Builtin] = &builtins![
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Does the opposite of `&`
|
/// Does the opposite of `&`
|
||||||
fn deref(tail) @env {
|
fn deref(tail) {
|
||||||
|
use std::rc::Rc;
|
||||||
Ok(match tail {
|
Ok(match tail {
|
||||||
ConValue::Ref(v) => env.get_id(*v).cloned().ok_or(Error::StackOverflow(*v))?,
|
ConValue::Ref(v) => Rc::as_ref(v).clone(),
|
||||||
_ => tail.clone(),
|
_ => tail.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
Callable,
|
|
||||||
convalue::ConValue,
|
|
||||||
env::Environment,
|
|
||||||
error::{Error, ErrorKind, IResult},
|
|
||||||
function::collect_upvars::CollectUpvars,
|
|
||||||
interpret::Interpret,
|
|
||||||
pattern,
|
|
||||||
};
|
|
||||||
use cl_ast::{Sym, ast_visitor::Visit};
|
|
||||||
use std::{collections::HashMap, fmt::Display};
|
|
||||||
|
|
||||||
/// Represents an ad-hoc anonymous function
|
|
||||||
/// which captures surrounding state by COPY
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Closure {
|
|
||||||
decl: cl_ast::Closure,
|
|
||||||
lift: HashMap<Sym, Option<ConValue>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Closure {
|
|
||||||
const NAME: &'static str = "{closure}";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Closure {
|
|
||||||
pub fn new(env: &mut Environment, decl: &cl_ast::Closure) -> Self {
|
|
||||||
let lift = CollectUpvars::new(env).visit(decl).finish_copied();
|
|
||||||
Self { decl: decl.clone(), lift }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Closure {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { decl, lift: _ } = self;
|
|
||||||
write!(f, "{decl}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Callable for Closure {
|
|
||||||
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
|
|
||||||
let Self { decl, lift } = self;
|
|
||||||
let mut env = env.frame(Self::NAME);
|
|
||||||
|
|
||||||
// place lifts in scope
|
|
||||||
for (name, value) in lift.clone() {
|
|
||||||
env.insert(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut env = env.frame("args");
|
|
||||||
|
|
||||||
for (name, value) in pattern::substitution(&decl.arg, ConValue::Tuple(args.into()))? {
|
|
||||||
env.insert(*name, Some(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = decl.body.interpret(&mut env);
|
|
||||||
drop(env);
|
|
||||||
|
|
||||||
match res {
|
|
||||||
Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
|
|
||||||
Err(Error { kind: ErrorKind::Break(value), .. }) => Err(Error::BadBreak(value)),
|
|
||||||
other => other,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> cl_ast::Sym {
|
|
||||||
"{closure}".into()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +1,15 @@
|
|||||||
//! Values in the dynamically typed AST interpreter.
|
//! Values in the dynamically typed AST interpreter.
|
||||||
//!
|
//!
|
||||||
//! The most permanent fix is a temporary one.
|
//! The most permanent fix is a temporary one.
|
||||||
use cl_ast::{Expr, Sym, format::FmtAdapter};
|
use cl_ast::{format::FmtAdapter, ExprKind, Sym};
|
||||||
|
|
||||||
use crate::{closure::Closure, env::Place};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Callable, Environment,
|
|
||||||
builtin::Builtin,
|
builtin::Builtin,
|
||||||
error::{Error, IResult},
|
error::{Error, IResult},
|
||||||
function::Function,
|
function::Function, Callable, Environment,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, ops::*, rc::Rc};
|
use std::{collections::HashMap, ops::*, rc::Rc};
|
||||||
|
|
||||||
/*
|
|
||||||
A Value can be:
|
|
||||||
- A Primitive (Empty, isize, etc.)
|
|
||||||
- A Record (Array, Tuple, Struct)
|
|
||||||
- A Variant (discriminant, Value) pair
|
|
||||||
|
|
||||||
array [
|
|
||||||
10, // 0
|
|
||||||
20, // 1
|
|
||||||
]
|
|
||||||
|
|
||||||
tuple (
|
|
||||||
10, // 0
|
|
||||||
20, // 1
|
|
||||||
)
|
|
||||||
|
|
||||||
struct {
|
|
||||||
x: 10, // x => 0
|
|
||||||
y: 20, // y => 1
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
type Integer = isize;
|
type Integer = isize;
|
||||||
|
|
||||||
/// A Conlang value stores data in the interpreter
|
/// A Conlang value stores data in the interpreter
|
||||||
@ -54,25 +29,23 @@ pub enum ConValue {
|
|||||||
/// A string
|
/// A string
|
||||||
String(Sym),
|
String(Sym),
|
||||||
/// A reference
|
/// A reference
|
||||||
Ref(Place),
|
Ref(Rc<ConValue>),
|
||||||
/// A reference to an array
|
|
||||||
Slice(Place, usize),
|
|
||||||
/// An Array
|
/// An Array
|
||||||
Array(Box<[ConValue]>),
|
Array(Box<[ConValue]>),
|
||||||
/// A tuple
|
/// A tuple
|
||||||
Tuple(Box<[ConValue]>),
|
Tuple(Box<[ConValue]>),
|
||||||
|
/// An exclusive range
|
||||||
|
RangeExc(Integer, Integer),
|
||||||
|
/// An inclusive range
|
||||||
|
RangeInc(Integer, Integer),
|
||||||
/// A value of a product type
|
/// A value of a product type
|
||||||
Struct(Box<(Sym, HashMap<Sym, ConValue>)>),
|
Struct(Box<(Sym, HashMap<Sym, ConValue>)>),
|
||||||
/// A value of a product type with anonymous members
|
|
||||||
TupleStruct(Box<(&'static str, Box<[ConValue]>)>),
|
|
||||||
/// An entire namespace
|
/// An entire namespace
|
||||||
Module(Box<HashMap<Sym, Option<ConValue>>>),
|
Module(Box<HashMap<Sym, Option<ConValue>>>),
|
||||||
/// A quoted expression
|
/// A quoted expression
|
||||||
Quote(Box<Expr>),
|
Quote(Box<ExprKind>),
|
||||||
/// A callable thing
|
/// A callable thing
|
||||||
Function(Rc<Function>),
|
Function(Rc<Function>),
|
||||||
/// A closure, capturing by reference
|
|
||||||
Closure(Rc<Closure>),
|
|
||||||
/// A built-in function
|
/// A built-in function
|
||||||
Builtin(&'static Builtin),
|
Builtin(&'static Builtin),
|
||||||
}
|
}
|
||||||
@ -82,22 +55,24 @@ impl ConValue {
|
|||||||
pub fn truthy(&self) -> IResult<bool> {
|
pub fn truthy(&self) -> IResult<bool> {
|
||||||
match self {
|
match self {
|
||||||
ConValue::Bool(v) => Ok(*v),
|
ConValue::Bool(v) => Ok(*v),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn range_exc(self, other: Self) -> IResult<Self> {
|
||||||
#[allow(non_snake_case)]
|
let (Self::Int(a), Self::Int(b)) = (self, other) else {
|
||||||
pub fn TupleStruct(name: Sym, values: Box<[ConValue]>) -> Self {
|
Err(Error::TypeError)?
|
||||||
Self::TupleStruct(Box::new((name.to_ref(), values)))
|
};
|
||||||
|
Ok(Self::RangeExc(a, b))
|
||||||
}
|
}
|
||||||
#[allow(non_snake_case)]
|
pub fn range_inc(self, other: Self) -> IResult<Self> {
|
||||||
pub fn Struct(name: Sym, values: HashMap<Sym, ConValue>) -> Self {
|
let (Self::Int(a), Self::Int(b)) = (self, other) else {
|
||||||
Self::Struct(Box::new((name, values)))
|
Err(Error::TypeError)?
|
||||||
|
};
|
||||||
|
Ok(Self::RangeInc(a, b))
|
||||||
}
|
}
|
||||||
|
pub fn index(&self, index: &Self) -> IResult<ConValue> {
|
||||||
pub fn index(&self, index: &Self, env: &Environment) -> IResult<ConValue> {
|
|
||||||
let Self::Int(index) = index else {
|
let Self::Int(index) = index else {
|
||||||
Err(Error::TypeError())?
|
Err(Error::TypeError)?
|
||||||
};
|
};
|
||||||
match self {
|
match self {
|
||||||
ConValue::String(string) => string
|
ConValue::String(string) => string
|
||||||
@ -109,11 +84,7 @@ impl ConValue {
|
|||||||
.get(*index as usize)
|
.get(*index as usize)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(Error::OobIndex(*index as usize, arr.len())),
|
.ok_or(Error::OobIndex(*index as usize, arr.len())),
|
||||||
ConValue::Slice(id, start) => env
|
_ => Err(Error::TypeError),
|
||||||
.get_id(*id)
|
|
||||||
.ok_or(Error::StackOverflow(*id))?
|
|
||||||
.index(&ConValue::Int((*index as usize + start) as isize), env),
|
|
||||||
_ => Err(Error::TypeError()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmp! {
|
cmp! {
|
||||||
@ -142,7 +113,6 @@ impl Callable for ConValue {
|
|||||||
fn name(&self) -> Sym {
|
fn name(&self) -> Sym {
|
||||||
match self {
|
match self {
|
||||||
ConValue::Function(func) => func.name(),
|
ConValue::Function(func) => func.name(),
|
||||||
ConValue::Closure(func) => func.name(),
|
|
||||||
ConValue::Builtin(func) => func.name(),
|
ConValue::Builtin(func) => func.name(),
|
||||||
_ => "".into(),
|
_ => "".into(),
|
||||||
}
|
}
|
||||||
@ -150,7 +120,6 @@ impl Callable for ConValue {
|
|||||||
fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
|
fn call(&self, interpreter: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
|
||||||
match self {
|
match self {
|
||||||
Self::Function(func) => func.call(interpreter, args),
|
Self::Function(func) => func.call(interpreter, args),
|
||||||
Self::Closure(func) => func.call(interpreter, args),
|
|
||||||
Self::Builtin(func) => func.call(interpreter, args),
|
Self::Builtin(func) => func.call(interpreter, args),
|
||||||
_ => Err(Error::NotCallable(self.clone())),
|
_ => Err(Error::NotCallable(self.clone())),
|
||||||
}
|
}
|
||||||
@ -168,7 +137,7 @@ macro cmp ($($fn:ident: $empty:literal, $op:tt);*$(;)?) {$(
|
|||||||
(Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
|
(Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
|
||||||
(Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
|
(Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
|
||||||
(Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
|
(Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
|
||||||
_ => Err(Error::TypeError())
|
_ => Err(Error::TypeError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*}
|
)*}
|
||||||
@ -196,9 +165,9 @@ from! {
|
|||||||
char => ConValue::Char,
|
char => ConValue::Char,
|
||||||
Sym => ConValue::String,
|
Sym => ConValue::String,
|
||||||
&str => ConValue::String,
|
&str => ConValue::String,
|
||||||
Expr => ConValue::Quote,
|
|
||||||
String => ConValue::String,
|
String => ConValue::String,
|
||||||
Rc<str> => ConValue::String,
|
Rc<str> => ConValue::String,
|
||||||
|
ExprKind => ConValue::Quote,
|
||||||
Function => ConValue::Function,
|
Function => ConValue::Function,
|
||||||
Vec<ConValue> => ConValue::Tuple,
|
Vec<ConValue> => ConValue::Tuple,
|
||||||
&'static Builtin => ConValue::Builtin,
|
&'static Builtin => ConValue::Builtin,
|
||||||
@ -210,9 +179,9 @@ impl From<()> for ConValue {
|
|||||||
}
|
}
|
||||||
impl From<&[ConValue]> for ConValue {
|
impl From<&[ConValue]> for ConValue {
|
||||||
fn from(value: &[ConValue]) -> Self {
|
fn from(value: &[ConValue]) -> Self {
|
||||||
match value {
|
match value.len() {
|
||||||
[] => Self::Empty,
|
0 => Self::Empty,
|
||||||
[value] => value.clone(),
|
1 => value[0].clone(),
|
||||||
_ => Self::Tuple(value.into()),
|
_ => Self::Tuple(value.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,25 +207,25 @@ ops! {
|
|||||||
(ConValue::Char(a), ConValue::Char(b)) => {
|
(ConValue::Char(a), ConValue::Char(b)) => {
|
||||||
ConValue::String([a, b].into_iter().collect::<String>().into())
|
ConValue::String([a, b].into_iter().collect::<String>().into())
|
||||||
}
|
}
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
BitAnd: bitand = [
|
BitAnd: bitand = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
BitOr: bitor = [
|
BitOr: bitor = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
BitXor: bitxor = [
|
BitXor: bitxor = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
Div: div = [
|
Div: div = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
@ -264,13 +233,13 @@ ops! {
|
|||||||
eprintln!("Warning: Divide by zero in {a} / {b}"); a
|
eprintln!("Warning: Divide by zero in {a} / {b}"); a
|
||||||
})),
|
})),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
Mul: mul = [
|
Mul: mul = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
Rem: rem = [
|
Rem: rem = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
@ -278,23 +247,23 @@ ops! {
|
|||||||
println!("Warning: Divide by zero in {a} % {b}"); a
|
println!("Warning: Divide by zero in {a} % {b}"); a
|
||||||
})),
|
})),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
Shl: shl = [
|
Shl: shl = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
Shr: shr = [
|
Shr: shr = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
Sub: sub = [
|
Sub: sub = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
|
||||||
_ => Err(Error::TypeError())?
|
_ => Err(Error::TypeError)?
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for ConValue {
|
impl std::fmt::Display for ConValue {
|
||||||
@ -306,8 +275,7 @@ impl std::fmt::Display for ConValue {
|
|||||||
ConValue::Bool(v) => v.fmt(f),
|
ConValue::Bool(v) => v.fmt(f),
|
||||||
ConValue::Char(v) => v.fmt(f),
|
ConValue::Char(v) => v.fmt(f),
|
||||||
ConValue::String(v) => v.fmt(f),
|
ConValue::String(v) => v.fmt(f),
|
||||||
ConValue::Ref(v) => write!(f, "&<{}>", v),
|
ConValue::Ref(v) => write!(f, "&{v}"),
|
||||||
ConValue::Slice(v, len) => write!(f, "&<{v}>[{len}..]"),
|
|
||||||
ConValue::Array(array) => {
|
ConValue::Array(array) => {
|
||||||
'['.fmt(f)?;
|
'['.fmt(f)?;
|
||||||
for (idx, element) in array.iter().enumerate() {
|
for (idx, element) in array.iter().enumerate() {
|
||||||
@ -318,6 +286,8 @@ impl std::fmt::Display for ConValue {
|
|||||||
}
|
}
|
||||||
']'.fmt(f)
|
']'.fmt(f)
|
||||||
}
|
}
|
||||||
|
ConValue::RangeExc(a, b) => write!(f, "{a}..{}", b + 1),
|
||||||
|
ConValue::RangeInc(a, b) => write!(f, "{a}..={b}"),
|
||||||
ConValue::Tuple(tuple) => {
|
ConValue::Tuple(tuple) => {
|
||||||
'('.fmt(f)?;
|
'('.fmt(f)?;
|
||||||
for (idx, element) in tuple.iter().enumerate() {
|
for (idx, element) in tuple.iter().enumerate() {
|
||||||
@ -328,25 +298,11 @@ impl std::fmt::Display for ConValue {
|
|||||||
}
|
}
|
||||||
')'.fmt(f)
|
')'.fmt(f)
|
||||||
}
|
}
|
||||||
ConValue::TupleStruct(parts) => {
|
|
||||||
let (name, tuple) = parts.as_ref();
|
|
||||||
if !name.is_empty() {
|
|
||||||
write!(f, "{name}")?;
|
|
||||||
}
|
|
||||||
'('.fmt(f)?;
|
|
||||||
for (idx, element) in tuple.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
", ".fmt(f)?
|
|
||||||
}
|
|
||||||
element.fmt(f)?
|
|
||||||
}
|
|
||||||
')'.fmt(f)
|
|
||||||
}
|
|
||||||
ConValue::Struct(parts) => {
|
ConValue::Struct(parts) => {
|
||||||
let (name, map) = parts.as_ref();
|
let (name, map) = parts.as_ref();
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
write!(f, "{name} ")?;
|
write!(f, "{name}: ")?;
|
||||||
}
|
}
|
||||||
let mut f = f.delimit_with("{", "\n}");
|
let mut f = f.delimit_with("{", "\n}");
|
||||||
for (k, v) in map.iter() {
|
for (k, v) in map.iter() {
|
||||||
@ -372,22 +328,9 @@ impl std::fmt::Display for ConValue {
|
|||||||
ConValue::Function(func) => {
|
ConValue::Function(func) => {
|
||||||
write!(f, "{}", func.decl())
|
write!(f, "{}", func.decl())
|
||||||
}
|
}
|
||||||
ConValue::Closure(func) => {
|
|
||||||
write!(f, "{}", func.as_ref())
|
|
||||||
}
|
|
||||||
ConValue::Builtin(func) => {
|
ConValue::Builtin(func) => {
|
||||||
write!(f, "{}", func.description())
|
write!(f, "{}", func.description())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub macro cvstruct (
|
|
||||||
$Name:ident {
|
|
||||||
$($member:ident : $expr:expr),*
|
|
||||||
}
|
|
||||||
) {{
|
|
||||||
let mut members = HashMap::new();
|
|
||||||
$(members.insert(stringify!($member).into(), ($expr).into());)*
|
|
||||||
ConValue::Struct(Box::new((stringify!($Name).into(), members)))
|
|
||||||
}}
|
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
use crate::builtin::Builtin;
|
use crate::builtin::Builtin;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Callable, Interpret,
|
|
||||||
builtin::{Builtins, Math},
|
builtin::{Builtins, Math},
|
||||||
convalue::ConValue,
|
convalue::ConValue,
|
||||||
error::{Error, IResult},
|
error::{Error, IResult},
|
||||||
function::Function,
|
function::Function,
|
||||||
|
Callable, Interpret,
|
||||||
};
|
};
|
||||||
use cl_ast::{Function as FnDecl, Sym};
|
use cl_ast::{Function as FnDecl, Sym};
|
||||||
use std::{
|
use std::{
|
||||||
@ -19,51 +19,30 @@ use std::{
|
|||||||
|
|
||||||
type StackFrame = HashMap<Sym, Option<ConValue>>;
|
type StackFrame = HashMap<Sym, Option<ConValue>>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub enum Place {
|
|
||||||
Global(Sym),
|
|
||||||
Local(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Place {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Place::Global(name) => name.fmt(f),
|
|
||||||
Place::Local(id) => id.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
|
||||||
struct EnvFrame {
|
|
||||||
/// The length of the array when this stack frame was constructed
|
|
||||||
pub name: Option<&'static str>,
|
|
||||||
pub base: usize,
|
|
||||||
pub binds: HashMap<Sym, usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements a nested lexical scope
|
/// Implements a nested lexical scope
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
global: HashMap<Sym, Option<ConValue>>,
|
builtin: StackFrame,
|
||||||
values: Vec<Option<ConValue>>,
|
global: Vec<(StackFrame, &'static str)>,
|
||||||
frames: Vec<EnvFrame>,
|
frames: Vec<(StackFrame, &'static str)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Environment {
|
impl Display for Environment {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
for EnvFrame { name, base: _, binds } in self.frames.iter().rev() {
|
for (frame, name) in self
|
||||||
writeln!(
|
.global
|
||||||
f,
|
.iter()
|
||||||
"--- {} ---",
|
.rev()
|
||||||
if let Some(name) = name { name } else { "" }
|
.take(2)
|
||||||
)?;
|
.rev()
|
||||||
for (var, val) in binds {
|
.chain(self.frames.iter())
|
||||||
|
{
|
||||||
|
writeln!(f, "--- {name} ---")?;
|
||||||
|
for (var, val) in frame {
|
||||||
write!(f, "{var}: ")?;
|
write!(f, "{var}: ")?;
|
||||||
match self.values.get(*val) {
|
match val {
|
||||||
Some(Some(value)) => writeln!(f, "\t{value}"),
|
Some(value) => writeln!(f, "\t{value}"),
|
||||||
Some(None) => writeln!(f, "<undefined>"),
|
None => writeln!(f, "<undefined>"),
|
||||||
None => writeln!(f, "ERROR: {var} address blows the stack!"),
|
|
||||||
}?
|
}?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,11 +51,19 @@ impl Display for Environment {
|
|||||||
}
|
}
|
||||||
impl Default for Environment {
|
impl Default for Environment {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut this = Self::no_builtins();
|
Self {
|
||||||
this.add_builtins(Builtins).add_builtins(Math);
|
builtin: to_hashmap(Builtins.iter().chain(Math.iter())),
|
||||||
this
|
global: vec![(HashMap::new(), "globals")],
|
||||||
|
frames: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_hashmap(from: impl IntoIterator<Item = &'static Builtin>) -> HashMap<Sym, Option<ConValue>> {
|
||||||
|
from.into_iter()
|
||||||
|
.map(|v| (v.name(), Some(v.into())))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -84,10 +71,36 @@ impl Environment {
|
|||||||
}
|
}
|
||||||
/// Creates an [Environment] with no [builtins](super::builtin)
|
/// Creates an [Environment] with no [builtins](super::builtin)
|
||||||
pub fn no_builtins() -> Self {
|
pub fn no_builtins() -> Self {
|
||||||
Self { values: Vec::new(), global: HashMap::new(), frames: vec![] }
|
Self {
|
||||||
|
builtin: HashMap::new(),
|
||||||
|
global: vec![(Default::default(), "globals")],
|
||||||
|
frames: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtins(&self) -> &StackFrame {
|
||||||
|
&self.builtin
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_builtin(&mut self, builtin: &'static Builtin) -> &mut Self {
|
||||||
|
self.builtin.insert(builtin.name(), Some(builtin.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_builtins(&mut self, builtins: &'static [Builtin]) {
|
||||||
|
for builtin in builtins {
|
||||||
|
self.add_builtin(builtin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_frame(&mut self, name: &'static str, frame: StackFrame) {
|
||||||
|
self.frames.push((frame, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_frame(&mut self) -> Option<(StackFrame, &'static str)> {
|
||||||
|
self.frames.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reflexively evaluates a node
|
|
||||||
pub fn eval(&mut self, node: &impl Interpret) -> IResult<ConValue> {
|
pub fn eval(&mut self, node: &impl Interpret) -> IResult<ConValue> {
|
||||||
node.interpret(self)
|
node.interpret(self)
|
||||||
}
|
}
|
||||||
@ -95,153 +108,102 @@ impl Environment {
|
|||||||
/// Calls a function inside the interpreter's scope,
|
/// Calls a function inside the interpreter's scope,
|
||||||
/// and returns the result
|
/// and returns the result
|
||||||
pub fn call(&mut self, name: Sym, args: &[ConValue]) -> IResult<ConValue> {
|
pub fn call(&mut self, name: Sym, args: &[ConValue]) -> IResult<ConValue> {
|
||||||
let function = self.get(name)?;
|
// FIXME: Clone to satisfy the borrow checker
|
||||||
|
let function = self.get(name)?.clone();
|
||||||
function.call(self, args)
|
function.call(self, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Binds a value to the given name in the current scope.
|
|
||||||
pub fn bind(&mut self, name: &str, value: impl Into<ConValue>) {
|
|
||||||
self.insert(name.into(), Some(value.into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets all registered globals, bound or unbound.
|
|
||||||
pub fn globals(&self) -> &HashMap<Sym, Option<ConValue>> {
|
|
||||||
&self.global
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds builtins
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Will panic if globals table is non-empty!
|
|
||||||
pub fn add_builtins(&mut self, builtins: &'static [Builtin]) -> &mut Self {
|
|
||||||
let Self { global, .. } = self;
|
|
||||||
for builtin in builtins {
|
|
||||||
global.insert(builtin.name(), Some(builtin.into()));
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_frame(&mut self, name: &'static str, frame: StackFrame) {
|
|
||||||
self.enter(name);
|
|
||||||
for (k, v) in frame {
|
|
||||||
self.insert(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_frame(&mut self) -> Option<(StackFrame, &'static str)> {
|
|
||||||
let mut out = HashMap::new();
|
|
||||||
let EnvFrame { name, base, binds } = self.frames.pop()?;
|
|
||||||
for (k, v) in binds {
|
|
||||||
out.insert(k, self.values.get_mut(v).and_then(std::mem::take));
|
|
||||||
}
|
|
||||||
self.values.truncate(base);
|
|
||||||
Some((out, name.unwrap_or("")))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enters a nested scope, returning a [`Frame`] stack-guard.
|
/// Enters a nested scope, returning a [`Frame`] stack-guard.
|
||||||
///
|
///
|
||||||
/// [`Frame`] implements Deref/DerefMut for [`Environment`].
|
/// [`Frame`] implements Deref/DerefMut for [`Environment`].
|
||||||
pub fn frame(&mut self, name: &'static str) -> Frame {
|
pub fn frame(&mut self, name: &'static str) -> Frame {
|
||||||
Frame::new(self, name)
|
Frame::new(self, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves a variable mutably.
|
/// Resolves a variable mutably.
|
||||||
///
|
///
|
||||||
/// Returns a mutable reference to the variable's record, if it exists.
|
/// Returns a mutable reference to the variable's record, if it exists.
|
||||||
pub fn get_mut(&mut self, name: Sym) -> IResult<&mut Option<ConValue>> {
|
pub fn get_mut(&mut self, id: Sym) -> IResult<&mut Option<ConValue>> {
|
||||||
let at = self.id_of(name)?;
|
for (frame, _) in self.frames.iter_mut().rev() {
|
||||||
self.get_id_mut(at).ok_or(Error::NotDefined(name))
|
if let Some(var) = frame.get_mut(&id) {
|
||||||
|
return Ok(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (frame, _) in self.global.iter_mut().rev() {
|
||||||
|
if let Some(var) = frame.get_mut(&id) {
|
||||||
|
return Ok(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.builtin.get_mut(&id).ok_or(Error::NotDefined(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves a variable immutably.
|
/// Resolves a variable immutably.
|
||||||
///
|
///
|
||||||
/// Returns a reference to the variable's contents, if it is defined and initialized.
|
/// Returns a reference to the variable's contents, if it is defined and initialized.
|
||||||
pub fn get(&self, name: Sym) -> IResult<ConValue> {
|
pub fn get(&self, id: Sym) -> IResult<ConValue> {
|
||||||
let id = self.id_of(name)?;
|
for (frame, _) in self.frames.iter().rev() {
|
||||||
let res = match id {
|
match frame.get(&id) {
|
||||||
Place::Global(name) => self.global.get(&name),
|
Some(Some(var)) => return Ok(var.clone()),
|
||||||
Place::Local(id) => self.values.get(id),
|
Some(None) => return Err(Error::NotInitialized(id)),
|
||||||
};
|
_ => (),
|
||||||
match res.ok_or(Error::NotDefined(name))? {
|
|
||||||
Some(value) => Ok(value.clone()),
|
|
||||||
None => Err(Error::NotInitialized(name)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (frame, _) in self.global.iter().rev() {
|
||||||
|
match frame.get(&id) {
|
||||||
|
Some(Some(var)) => return Ok(var.clone()),
|
||||||
|
Some(None) => return Err(Error::NotInitialized(id)),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.builtin
|
||||||
|
.get(&id)
|
||||||
|
.cloned()
|
||||||
|
.flatten()
|
||||||
|
.ok_or(Error::NotDefined(id))
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolves the [Place] associated with a [Sym]
|
pub(crate) fn get_local(&self, id: Sym) -> IResult<ConValue> {
|
||||||
pub fn id_of(&self, name: Sym) -> IResult<Place> {
|
for (frame, _) in self.frames.iter().rev() {
|
||||||
for EnvFrame { binds, .. } in self.frames.iter().rev() {
|
match frame.get(&id) {
|
||||||
if let Some(id) = binds.get(&name).copied() {
|
Some(Some(var)) => return Ok(var.clone()),
|
||||||
return Ok(Place::Local(id));
|
Some(None) => return Err(Error::NotInitialized(id)),
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Place::Global(name))
|
Err(Error::NotInitialized(id))
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_id(&self, at: Place) -> Option<&ConValue> {
|
|
||||||
let res = match at {
|
|
||||||
Place::Global(name) => self.global.get(&name),
|
|
||||||
Place::Local(id) => self.values.get(id),
|
|
||||||
}?;
|
|
||||||
res.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_id_mut(&mut self, at: Place) -> Option<&mut Option<ConValue>> {
|
|
||||||
match at {
|
|
||||||
Place::Global(name) => self.global.get_mut(&name),
|
|
||||||
Place::Local(id) => self.values.get_mut(id),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a new [ConValue] into this [Environment]
|
/// Inserts a new [ConValue] into this [Environment]
|
||||||
pub fn insert(&mut self, k: Sym, v: Option<ConValue>) {
|
pub fn insert(&mut self, id: Sym, value: Option<ConValue>) {
|
||||||
if self.bind_raw(k, self.values.len()).is_some() {
|
if let Some((frame, _)) = self.frames.last_mut() {
|
||||||
self.values.push(v);
|
frame.insert(id, value);
|
||||||
} else {
|
} else if let Some((frame, _)) = self.global.last_mut() {
|
||||||
self.global.insert(k, v);
|
frame.insert(id, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convenience function for registering a [FnDecl] as a [Function]
|
/// A convenience function for registering a [FnDecl] as a [Function]
|
||||||
pub fn insert_fn(&mut self, decl: &FnDecl) {
|
pub fn insert_fn(&mut self, decl: &FnDecl) {
|
||||||
let FnDecl { name, .. } = decl;
|
let FnDecl { name, .. } = decl;
|
||||||
let (name, function) = (*name, Rc::new(Function::new(decl)));
|
let (name, function) = (name, Rc::new(Function::new(decl)));
|
||||||
self.insert(name, Some(ConValue::Function(function.clone())));
|
if let Some((frame, _)) = self.frames.last_mut() {
|
||||||
|
frame.insert(*name, Some(ConValue::Function(function.clone())));
|
||||||
|
} else if let Some((frame, _)) = self.global.last_mut() {
|
||||||
|
frame.insert(*name, Some(ConValue::Function(function.clone())));
|
||||||
|
}
|
||||||
// Tell the function to lift its upvars now, after it's been declared
|
// Tell the function to lift its upvars now, after it's been declared
|
||||||
function.lift_upvars(self);
|
function.lift_upvars(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates a local variable
|
|
||||||
pub fn stack_alloc(&mut self, value: ConValue) -> IResult<usize> {
|
|
||||||
let adr = self.values.len();
|
|
||||||
self.values.push(Some(value));
|
|
||||||
Ok(adr)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bind_raw(&mut self, name: Sym, id: usize) -> Option<()> {
|
|
||||||
let EnvFrame { name: _, base: _, binds } = self.frames.last_mut()?;
|
|
||||||
binds.insert(name, id);
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Functions which aid in the implementation of [`Frame`]
|
/// Functions which aid in the implementation of [`Frame`]
|
||||||
impl Environment {
|
impl Environment {
|
||||||
/// Enters a scope, creating a new namespace for variables
|
/// Enters a scope, creating a new namespace for variables
|
||||||
fn enter(&mut self, name: &'static str) -> &mut Self {
|
fn enter(&mut self, name: &'static str) -> &mut Self {
|
||||||
let new_frame =
|
self.frames.push((Default::default(), name));
|
||||||
EnvFrame { name: Some(name), base: self.values.len(), binds: HashMap::new() };
|
|
||||||
self.frames.push(new_frame);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exits the scope, destroying all local variables and
|
/// Exits the scope, destroying all local variables and
|
||||||
/// returning the outer scope, if there is one
|
/// returning the outer scope, if there is one
|
||||||
fn exit(&mut self) -> &mut Self {
|
fn exit(&mut self) -> &mut Self {
|
||||||
if let Some(frame) = self.frames.pop() {
|
self.frames.pop();
|
||||||
self.values.truncate(frame.base);
|
|
||||||
}
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,123 +1,14 @@
|
|||||||
//! The [Error] type represents any error thrown by the [Environment](super::Environment)
|
//! The [Error] type represents any error thrown by the [Environment](super::Environment)
|
||||||
|
|
||||||
use cl_ast::{Pattern, Sym};
|
use cl_ast::{Pattern, Sym};
|
||||||
use cl_structures::span::Span;
|
|
||||||
|
|
||||||
use super::{convalue::ConValue, env::Place};
|
use super::convalue::ConValue;
|
||||||
|
|
||||||
pub type IResult<T> = Result<T, Error>;
|
pub type IResult<T> = Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Error {
|
|
||||||
pub kind: ErrorKind,
|
|
||||||
span: Option<Span>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error {
|
|
||||||
#![allow(non_snake_case)]
|
|
||||||
|
|
||||||
/// Adds a [Span] to this [Error], if there isn't already a more specific one.
|
|
||||||
pub fn with_span(self, span: Span) -> Self {
|
|
||||||
Self { span: self.span.or(Some(span)), ..self }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> &ErrorKind {
|
|
||||||
&self.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Propagate a Return value
|
|
||||||
pub fn Return(value: ConValue) -> Self {
|
|
||||||
Self { kind: ErrorKind::Return(value), span: None }
|
|
||||||
}
|
|
||||||
/// Propagate a Break value
|
|
||||||
pub fn Break(value: ConValue) -> Self {
|
|
||||||
Self { kind: ErrorKind::Break(value), span: None }
|
|
||||||
}
|
|
||||||
/// Break propagated across function bounds
|
|
||||||
pub fn BadBreak(value: ConValue) -> Self {
|
|
||||||
Self { kind: ErrorKind::BadBreak(value), span: None }
|
|
||||||
}
|
|
||||||
/// Continue to the next iteration of a loop
|
|
||||||
pub fn Continue() -> Self {
|
|
||||||
Self { kind: ErrorKind::Continue, span: None }
|
|
||||||
}
|
|
||||||
/// Underflowed the stack
|
|
||||||
pub fn StackUnderflow() -> Self {
|
|
||||||
Self { kind: ErrorKind::StackUnderflow, span: None }
|
|
||||||
}
|
|
||||||
/// Overflowed the stack
|
|
||||||
pub fn StackOverflow(place: Place) -> Self {
|
|
||||||
Self { kind: ErrorKind::StackOverflow(place), span: None }
|
|
||||||
}
|
|
||||||
/// Exited the last scope
|
|
||||||
pub fn ScopeExit() -> Self {
|
|
||||||
Self { kind: ErrorKind::ScopeExit, span: None }
|
|
||||||
}
|
|
||||||
/// Type incompatibility
|
|
||||||
// TODO: store the type information in this error
|
|
||||||
pub fn TypeError() -> Self {
|
|
||||||
Self { kind: ErrorKind::TypeError, span: None }
|
|
||||||
}
|
|
||||||
/// In clause of For loop didn't yield a Range
|
|
||||||
pub fn NotIterable() -> Self {
|
|
||||||
Self { kind: ErrorKind::NotIterable, span: None }
|
|
||||||
}
|
|
||||||
/// A value could not be indexed
|
|
||||||
pub fn NotIndexable() -> Self {
|
|
||||||
Self { kind: ErrorKind::NotIndexable, span: None }
|
|
||||||
}
|
|
||||||
/// An array index went out of bounds
|
|
||||||
pub fn OobIndex(index: usize, length: usize) -> Self {
|
|
||||||
Self { kind: ErrorKind::OobIndex(index, length), span: None }
|
|
||||||
}
|
|
||||||
/// An expression is not assignable
|
|
||||||
pub fn NotAssignable() -> Self {
|
|
||||||
Self { kind: ErrorKind::NotAssignable, span: None }
|
|
||||||
}
|
|
||||||
/// A name was not defined in scope before being used
|
|
||||||
pub fn NotDefined(name: Sym) -> Self {
|
|
||||||
Self { kind: ErrorKind::NotDefined(name), span: None }
|
|
||||||
}
|
|
||||||
/// A name was defined but not initialized
|
|
||||||
pub fn NotInitialized(name: Sym) -> Self {
|
|
||||||
Self { kind: ErrorKind::NotInitialized(name), span: None }
|
|
||||||
}
|
|
||||||
/// A value was called, but is not callable
|
|
||||||
pub fn NotCallable(value: ConValue) -> Self {
|
|
||||||
Self { kind: ErrorKind::NotCallable(value), span: None }
|
|
||||||
}
|
|
||||||
/// A function was called with the wrong number of arguments
|
|
||||||
pub fn ArgNumber(want: usize, got: usize) -> Self {
|
|
||||||
Self { kind: ErrorKind::ArgNumber { want, got }, span: None }
|
|
||||||
}
|
|
||||||
/// A pattern failed to match
|
|
||||||
pub fn PatFailed(pat: Box<Pattern>) -> Self {
|
|
||||||
Self { kind: ErrorKind::PatFailed(pat), span: None }
|
|
||||||
}
|
|
||||||
/// Fell through a non-exhaustive match
|
|
||||||
pub fn MatchNonexhaustive() -> Self {
|
|
||||||
Self { kind: ErrorKind::MatchNonexhaustive, span: None }
|
|
||||||
}
|
|
||||||
/// Error produced by a Builtin
|
|
||||||
pub fn BuiltinError(msg: String) -> Self {
|
|
||||||
Self { kind: ErrorKind::BuiltinError(msg), span: None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for Error {}
|
|
||||||
impl std::fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let Self { kind, span } = self;
|
|
||||||
if let Some(Span { head, tail }) = span {
|
|
||||||
write!(f, "{head}..{tail}: ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{kind}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents any error thrown by the [Environment](super::Environment)
|
/// Represents any error thrown by the [Environment](super::Environment)
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ErrorKind {
|
pub enum Error {
|
||||||
/// Propagate a Return value
|
/// Propagate a Return value
|
||||||
Return(ConValue),
|
Return(ConValue),
|
||||||
/// Propagate a Break value
|
/// Propagate a Break value
|
||||||
@ -128,8 +19,6 @@ pub enum ErrorKind {
|
|||||||
Continue,
|
Continue,
|
||||||
/// Underflowed the stack
|
/// Underflowed the stack
|
||||||
StackUnderflow,
|
StackUnderflow,
|
||||||
/// Overflowed the stack
|
|
||||||
StackOverflow(Place),
|
|
||||||
/// Exited the last scope
|
/// Exited the last scope
|
||||||
ScopeExit,
|
ScopeExit,
|
||||||
/// Type incompatibility
|
/// Type incompatibility
|
||||||
@ -156,56 +45,53 @@ pub enum ErrorKind {
|
|||||||
/// Fell through a non-exhaustive match
|
/// Fell through a non-exhaustive match
|
||||||
MatchNonexhaustive,
|
MatchNonexhaustive,
|
||||||
/// Error produced by a Builtin
|
/// Error produced by a Builtin
|
||||||
BuiltinError(String),
|
BuiltinDebug(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for ErrorKind {}
|
impl std::error::Error for Error {}
|
||||||
impl std::fmt::Display for ErrorKind {
|
impl std::fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ErrorKind::Return(value) => write!(f, "return {value}"),
|
Error::Return(value) => write!(f, "return {value}"),
|
||||||
ErrorKind::Break(value) => write!(f, "break {value}"),
|
Error::Break(value) => write!(f, "break {value}"),
|
||||||
ErrorKind::BadBreak(value) => write!(f, "rogue break: {value}"),
|
Error::BadBreak(value) => write!(f, "rogue break: {value}"),
|
||||||
ErrorKind::Continue => "continue".fmt(f),
|
Error::Continue => "continue".fmt(f),
|
||||||
ErrorKind::StackUnderflow => "Stack underflow".fmt(f),
|
Error::StackUnderflow => "Stack underflow".fmt(f),
|
||||||
ErrorKind::StackOverflow(id) => {
|
Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
|
||||||
write!(f, "Attempt to access <{id}> resulted in stack overflow.")
|
Error::TypeError => "Incompatible types".fmt(f),
|
||||||
}
|
Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
|
||||||
ErrorKind::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
|
Error::NotIndexable => {
|
||||||
ErrorKind::TypeError => "Incompatible types".fmt(f),
|
|
||||||
ErrorKind::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
|
|
||||||
ErrorKind::NotIndexable => {
|
|
||||||
write!(f, "expression cannot be indexed")
|
write!(f, "expression cannot be indexed")
|
||||||
}
|
}
|
||||||
ErrorKind::OobIndex(idx, len) => {
|
Error::OobIndex(idx, len) => {
|
||||||
write!(f, "Index out of bounds: index was {idx}. but len is {len}")
|
write!(f, "Index out of bounds: index was {idx}. but len is {len}")
|
||||||
}
|
}
|
||||||
ErrorKind::NotAssignable => {
|
Error::NotAssignable => {
|
||||||
write!(f, "expression is not assignable")
|
write!(f, "expression is not assignable")
|
||||||
}
|
}
|
||||||
ErrorKind::NotDefined(value) => {
|
Error::NotDefined(value) => {
|
||||||
write!(f, "{value} not bound. Did you mean `let {value};`?")
|
write!(f, "{value} not bound. Did you mean `let {value};`?")
|
||||||
}
|
}
|
||||||
ErrorKind::NotInitialized(value) => {
|
Error::NotInitialized(value) => {
|
||||||
write!(f, "{value} bound, but not initialized")
|
write!(f, "{value} bound, but not initialized")
|
||||||
}
|
}
|
||||||
ErrorKind::NotCallable(value) => {
|
Error::NotCallable(value) => {
|
||||||
write!(f, "{value} is not callable.")
|
write!(f, "{value} is not callable.")
|
||||||
}
|
}
|
||||||
ErrorKind::ArgNumber { want, got } => {
|
Error::ArgNumber { want, got } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Expected {want} argument{}, got {got}",
|
"Expected {want} argument{}, got {got}",
|
||||||
if *want == 1 { "" } else { "s" }
|
if *want == 1 { "" } else { "s" }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ErrorKind::PatFailed(pattern) => {
|
Error::PatFailed(pattern) => {
|
||||||
write!(f, "Failed to match pattern {pattern}")
|
write!(f, "Failed to match pattern {pattern}")
|
||||||
}
|
}
|
||||||
ErrorKind::MatchNonexhaustive => {
|
Error::MatchNonexhaustive => {
|
||||||
write!(f, "Fell through a non-exhaustive match expression!")
|
write!(f, "Fell through a non-exhaustive match expression!")
|
||||||
}
|
}
|
||||||
ErrorKind::BuiltinError(s) => write!(f, "{s}"),
|
Error::BuiltinDebug(s) => write!(f, "DEBUG: {s}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
use collect_upvars::collect_upvars;
|
use collect_upvars::collect_upvars;
|
||||||
|
|
||||||
use crate::error::ErrorKind;
|
use super::{Callable, ConValue, Environment, Error, IResult, Interpret};
|
||||||
|
use cl_ast::{Function as FnDecl, Param, Sym};
|
||||||
use super::{Callable, ConValue, Environment, Error, IResult, Interpret, pattern};
|
|
||||||
use cl_ast::{Function as FnDecl, Sym};
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -23,16 +21,12 @@ pub struct Function {
|
|||||||
decl: Rc<FnDecl>,
|
decl: Rc<FnDecl>,
|
||||||
/// Stores data from the enclosing scopes
|
/// Stores data from the enclosing scopes
|
||||||
upvars: RefCell<Upvars>,
|
upvars: RefCell<Upvars>,
|
||||||
is_constructor: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
pub fn new(decl: &FnDecl) -> Self {
|
pub fn new(decl: &FnDecl) -> Self {
|
||||||
// let upvars = collect_upvars(decl, env);
|
// let upvars = collect_upvars(decl, env);
|
||||||
Self { decl: decl.clone().into(), upvars: Default::default(), is_constructor: false }
|
Self { decl: decl.clone().into(), upvars: Default::default() }
|
||||||
}
|
|
||||||
pub fn new_constructor(decl: FnDecl) -> Self {
|
|
||||||
Self { decl: decl.into(), upvars: Default::default(), is_constructor: true }
|
|
||||||
}
|
}
|
||||||
pub fn decl(&self) -> &FnDecl {
|
pub fn decl(&self) -> &FnDecl {
|
||||||
&self.decl
|
&self.decl
|
||||||
@ -54,14 +48,11 @@ impl Callable for Function {
|
|||||||
name
|
name
|
||||||
}
|
}
|
||||||
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
|
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
|
||||||
let FnDecl { name, gens: _, bind, body, sign: _ } = &*self.decl;
|
let FnDecl { name, bind, body, sign: _ } = &*self.decl;
|
||||||
|
|
||||||
// Check arg mapping
|
// Check arg mapping
|
||||||
if self.is_constructor {
|
if args.len() != bind.len() {
|
||||||
return Ok(ConValue::TupleStruct(Box::new((
|
return Err(Error::ArgNumber { want: bind.len(), got: args.len() });
|
||||||
name.to_ref(),
|
|
||||||
args.into(),
|
|
||||||
))));
|
|
||||||
}
|
}
|
||||||
let Some(body) = body else {
|
let Some(body) = body else {
|
||||||
return Err(Error::NotDefined(*name));
|
return Err(Error::NotDefined(*name));
|
||||||
@ -72,8 +63,8 @@ impl Callable for Function {
|
|||||||
|
|
||||||
// TODO: completely refactor data storage
|
// TODO: completely refactor data storage
|
||||||
let mut frame = env.frame("fn args");
|
let mut frame = env.frame("fn args");
|
||||||
for (name, value) in pattern::substitution(bind, ConValue::Tuple(args.into()))? {
|
for (Param { mutability: _, name }, value) in bind.iter().zip(args) {
|
||||||
frame.insert(*name, Some(value));
|
frame.insert(*name, Some(value.clone()));
|
||||||
}
|
}
|
||||||
let res = body.interpret(&mut frame);
|
let res = body.interpret(&mut frame);
|
||||||
drop(frame);
|
drop(frame);
|
||||||
@ -81,9 +72,9 @@ impl Callable for Function {
|
|||||||
self.upvars.replace(upvars);
|
self.upvars.replace(upvars);
|
||||||
}
|
}
|
||||||
match res {
|
match res {
|
||||||
Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
|
Err(Error::Return(value)) => Ok(value),
|
||||||
Err(Error { kind: ErrorKind::Break(value), .. }) => Err(Error::BadBreak(value)),
|
Err(Error::Break(value)) => Err(Error::BadBreak(value)),
|
||||||
other => other,
|
result => result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
//! Collects the "Upvars" of a function at the point of its creation, allowing variable capture
|
//! Collects the "Upvars" of a function at the point of its creation, allowing variable capture
|
||||||
use crate::env::{Environment, Place};
|
use crate::{convalue::ConValue, env::Environment};
|
||||||
use cl_ast::{
|
use cl_ast::{ast_visitor::visit::*, Function, Let, Param, Path, PathPart, Pattern, Sym};
|
||||||
Function, Let, Path, PathPart, Pattern, Sym,
|
|
||||||
ast_visitor::{visit::*, walk::Walk},
|
|
||||||
};
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
pub fn collect_upvars(f: &Function, env: &Environment) -> super::Upvars {
|
pub fn collect_upvars(f: &Function, env: &Environment) -> super::Upvars {
|
||||||
CollectUpvars::new(env).visit(f).finish_copied()
|
CollectUpvars::new(env).get_upvars(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct CollectUpvars<'env> {
|
pub struct CollectUpvars<'env> {
|
||||||
env: &'env Environment,
|
env: &'env Environment,
|
||||||
upvars: HashMap<Sym, Place>,
|
upvars: HashMap<Sym, Option<ConValue>>,
|
||||||
blacklist: HashSet<Sym>,
|
blacklist: HashSet<Sym>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,17 +18,9 @@ impl<'env> CollectUpvars<'env> {
|
|||||||
pub fn new(env: &'env Environment) -> Self {
|
pub fn new(env: &'env Environment) -> Self {
|
||||||
Self { upvars: HashMap::new(), blacklist: HashSet::new(), env }
|
Self { upvars: HashMap::new(), blacklist: HashSet::new(), env }
|
||||||
}
|
}
|
||||||
|
pub fn get_upvars(mut self, f: &cl_ast::Function) -> HashMap<Sym, Option<ConValue>> {
|
||||||
pub fn finish(&mut self) -> HashMap<Sym, Place> {
|
self.visit_function(f);
|
||||||
std::mem::take(&mut self.upvars)
|
self.upvars
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish_copied(&mut self) -> super::Upvars {
|
|
||||||
let Self { env, upvars, blacklist: _ } = self;
|
|
||||||
std::mem::take(upvars)
|
|
||||||
.into_iter()
|
|
||||||
.map(|(k, v)| (k, env.get_id(v).cloned()))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_upvar(&mut self, name: &Sym) {
|
pub fn add_upvar(&mut self, name: &Sym) {
|
||||||
@ -39,8 +28,8 @@ impl<'env> CollectUpvars<'env> {
|
|||||||
if blacklist.contains(name) || upvars.contains_key(name) {
|
if blacklist.contains(name) || upvars.contains_key(name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Ok(place) = env.id_of(*name) {
|
if let Ok(upvar) = env.get_local(*name) {
|
||||||
upvars.insert(*name, place);
|
upvars.insert(*name, Some(upvar));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +43,8 @@ impl<'a> Visit<'a> for CollectUpvars<'_> {
|
|||||||
let blacklist = self.blacklist.clone();
|
let blacklist = self.blacklist.clone();
|
||||||
|
|
||||||
// visit the block
|
// visit the block
|
||||||
b.children(self);
|
let cl_ast::Block { stmts } = b;
|
||||||
|
stmts.iter().for_each(|s| self.visit_stmt(s));
|
||||||
|
|
||||||
// restore the blacklist
|
// restore the blacklist
|
||||||
self.blacklist = blacklist;
|
self.blacklist = blacklist;
|
||||||
@ -63,26 +53,33 @@ impl<'a> Visit<'a> for CollectUpvars<'_> {
|
|||||||
fn visit_let(&mut self, l: &'a cl_ast::Let) {
|
fn visit_let(&mut self, l: &'a cl_ast::Let) {
|
||||||
let Let { mutable, name, ty, init } = l;
|
let Let { mutable, name, ty, init } = l;
|
||||||
self.visit_mutability(mutable);
|
self.visit_mutability(mutable);
|
||||||
|
if let Some(ty) = ty {
|
||||||
ty.visit_in(self);
|
self.visit_ty(ty);
|
||||||
|
}
|
||||||
// visit the initializer, which may use the bound name
|
// visit the initializer, which may use the bound name
|
||||||
init.visit_in(self);
|
if let Some(init) = init {
|
||||||
|
self.visit_expr(init)
|
||||||
|
}
|
||||||
// a bound name can never be an upvar
|
// a bound name can never be an upvar
|
||||||
self.visit_pattern(name);
|
self.visit_pattern(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_function(&mut self, f: &'a cl_ast::Function) {
|
fn visit_function(&mut self, f: &'a cl_ast::Function) {
|
||||||
let Function { name: _, gens: _, sign: _, bind, body } = f;
|
let Function { name: _, sign: _, bind, body } = f;
|
||||||
// parameters can never be upvars
|
// parameters can never be upvars
|
||||||
bind.visit_in(self);
|
for Param { mutability: _, name } in bind {
|
||||||
body.visit_in(self);
|
self.bind_name(name);
|
||||||
|
}
|
||||||
|
if let Some(body) = body {
|
||||||
|
self.visit_block(body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_for(&mut self, f: &'a cl_ast::For) {
|
fn visit_for(&mut self, f: &'a cl_ast::For) {
|
||||||
let cl_ast::For { bind, cond, pass, fail } = f;
|
let cl_ast::For { bind, cond, pass, fail } = f;
|
||||||
self.visit_expr(cond);
|
self.visit_expr(cond);
|
||||||
self.visit_else(fail);
|
self.visit_else(fail);
|
||||||
self.visit_pattern(bind);
|
self.bind_name(bind); // TODO: is bind only bound in the pass block?
|
||||||
self.visit_block(pass);
|
self.visit_block(pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,11 +105,30 @@ impl<'a> Visit<'a> for CollectUpvars<'_> {
|
|||||||
|
|
||||||
fn visit_pattern(&mut self, p: &'a cl_ast::Pattern) {
|
fn visit_pattern(&mut self, p: &'a cl_ast::Pattern) {
|
||||||
match p {
|
match p {
|
||||||
Pattern::Name(name) => {
|
Pattern::Path(path) => {
|
||||||
self.bind_name(name);
|
if let [PathPart::Ident(name)] = path.parts.as_slice() {
|
||||||
|
self.bind_name(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pattern::Literal(literal) => self.visit_literal(literal),
|
||||||
|
Pattern::Ref(mutability, pattern) => {
|
||||||
|
self.visit_mutability(mutability);
|
||||||
|
self.visit_pattern(pattern);
|
||||||
|
}
|
||||||
|
Pattern::Tuple(patterns) => {
|
||||||
|
patterns.iter().for_each(|p| self.visit_pattern(p));
|
||||||
|
}
|
||||||
|
Pattern::Array(patterns) => {
|
||||||
|
patterns.iter().for_each(|p| self.visit_pattern(p));
|
||||||
|
}
|
||||||
|
Pattern::Struct(path, items) => {
|
||||||
|
self.visit_path(path);
|
||||||
|
items.iter().for_each(|(_name, bind)| {
|
||||||
|
bind.as_ref().inspect(|bind| {
|
||||||
|
self.visit_pattern(bind);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Pattern::RangeExc(_, _) | Pattern::RangeInc(_, _) => {}
|
|
||||||
_ => p.children(self),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
//! meaningless to get a pointer to one, and would be undefined behavior to dereference a pointer to
|
//! meaningless to get a pointer to one, and would be undefined behavior to dereference a pointer to
|
||||||
//! one in any situation.
|
//! one in any situation.
|
||||||
|
|
||||||
|
use std::{borrow::Borrow, rc::Rc};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use cl_ast::{ast_visitor::Visit, *};
|
use cl_ast::*;
|
||||||
use std::borrow::Borrow;
|
use cl_structures::intern::interned::Interned;
|
||||||
/// A work-in-progress tree walk interpreter for Conlang
|
/// A work-in-progress tree walk interpreter for Conlang
|
||||||
pub trait Interpret {
|
pub trait Interpret {
|
||||||
/// Interprets this thing in the given [`Environment`].
|
/// Interprets this thing in the given [`Environment`].
|
||||||
@ -18,30 +20,9 @@ pub trait Interpret {
|
|||||||
|
|
||||||
impl Interpret for File {
|
impl Interpret for File {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
/// Sorts items
|
for item in &self.items {
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct ItemSorter<'ast>(pub [Vec<&'ast Item>; 8]);
|
|
||||||
impl<'ast> Visit<'ast> for ItemSorter<'ast> {
|
|
||||||
fn visit_item(&mut self, i: &'ast Item) {
|
|
||||||
for stage in match &i.kind {
|
|
||||||
ItemKind::Module(_) => [0].as_slice(),
|
|
||||||
ItemKind::Use(_) => &[1, 6],
|
|
||||||
ItemKind::Enum(_) | ItemKind::Struct(_) | ItemKind::Alias(_) => &[2],
|
|
||||||
ItemKind::Function(_) => &[3, 7],
|
|
||||||
ItemKind::Impl(_) => &[4],
|
|
||||||
ItemKind::Const(_) | ItemKind::Static(_) => &[5],
|
|
||||||
} {
|
|
||||||
self.0[*stage].push(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut items = ItemSorter::default();
|
|
||||||
items.visit_file(self);
|
|
||||||
for item in items.0.into_iter().flatten() {
|
|
||||||
item.interpret(env)?;
|
item.interpret(env)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ConValue::Empty)
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,13 +66,12 @@ impl Interpret for Static {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Interpret for Module {
|
impl Interpret for Module {
|
||||||
// TODO: Keep modules around somehow, rather than putting them on the stack
|
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { name, file } = self;
|
let Self { name, kind } = self;
|
||||||
env.push_frame(name.to_ref(), Default::default());
|
env.push_frame(Interned::to_ref(name), Default::default());
|
||||||
let out = match file {
|
let out = match kind {
|
||||||
Some(file) => file.interpret(env),
|
ModuleKind::Inline(file) => file.interpret(env),
|
||||||
None => {
|
ModuleKind::Outline => {
|
||||||
eprintln!("Module {name} specified, but not imported.");
|
eprintln!("Module {name} specified, but not imported.");
|
||||||
Ok(ConValue::Empty)
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
@ -113,88 +93,22 @@ impl Interpret for Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Interpret for Struct {
|
impl Interpret for Struct {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { name, gens: _, kind } = self;
|
println!("TODO: {self}");
|
||||||
match kind {
|
|
||||||
StructKind::Empty => {}
|
|
||||||
StructKind::Tuple(args) => {
|
|
||||||
// Constructs the AST from scratch. TODO: This, better.
|
|
||||||
let constructor = Function {
|
|
||||||
name: *name,
|
|
||||||
gens: Default::default(),
|
|
||||||
sign: TyFn {
|
|
||||||
args: TyKind::Tuple(TyTuple {
|
|
||||||
types: args.iter().map(|ty| ty.kind.clone()).collect(),
|
|
||||||
})
|
|
||||||
.into(),
|
|
||||||
rety: Some(
|
|
||||||
Ty {
|
|
||||||
span: cl_structures::span::Span::dummy(),
|
|
||||||
kind: TyKind::Path(Path::from(*name)),
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
bind: Pattern::Tuple(
|
|
||||||
args.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, _)| Pattern::Name(idx.to_string().into()))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
body: None,
|
|
||||||
};
|
|
||||||
let constructor = crate::function::Function::new_constructor(constructor);
|
|
||||||
env.insert(*name, Some(constructor.into()));
|
|
||||||
}
|
|
||||||
StructKind::Struct(_) => eprintln!("TODO: {self}"),
|
|
||||||
}
|
|
||||||
Ok(ConValue::Empty)
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Interpret for Enum {
|
impl Interpret for Enum {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { name, gens: _, variants } = self;
|
println!("TODO: {self}");
|
||||||
env.push_frame(name.to_ref(), Default::default());
|
|
||||||
for (idx, Variant { name, kind, body }) in variants.iter().enumerate() {
|
|
||||||
match (kind, body) {
|
|
||||||
(StructKind::Empty, None) => env.insert(*name, Some(ConValue::Int(idx as _))),
|
|
||||||
(StructKind::Empty, Some(idx)) => {
|
|
||||||
let idx = idx.interpret(env)?;
|
|
||||||
env.insert(*name, Some(idx))
|
|
||||||
}
|
|
||||||
(StructKind::Tuple(_), None) => {}
|
|
||||||
(StructKind::Struct(_), None) => {}
|
|
||||||
_ => eprintln!("Well-formedness error in {self}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let (frame, _) = env
|
|
||||||
.pop_frame()
|
|
||||||
.expect("Frame stack should remain balanced.");
|
|
||||||
env.insert(*name, Some(ConValue::Module(Box::new(frame))));
|
|
||||||
Ok(ConValue::Empty)
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Interpret for Impl {
|
impl Interpret for Impl {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { target: ImplKind::Type(Ty { span, kind: TyKind::Path(name) }), body } = self
|
println!("TODO: {self}");
|
||||||
else {
|
let Self { target: _, body } = self;
|
||||||
eprintln!("TODO: impl X for Ty");
|
body.interpret(env)
|
||||||
return Ok(ConValue::Empty);
|
|
||||||
};
|
|
||||||
env.push_frame("impl", Default::default());
|
|
||||||
body.interpret(env)?;
|
|
||||||
|
|
||||||
let (frame, _) = env
|
|
||||||
.pop_frame()
|
|
||||||
.expect("Environment frames must be balanced");
|
|
||||||
match assignment::addrof_path(env, name.parts.as_slice())
|
|
||||||
.map_err(|err| err.with_span(*span))?
|
|
||||||
{
|
|
||||||
Some(ConValue::Module(m)) => m.extend(frame),
|
|
||||||
Some(other) => eprintln!("TODO: impl for {other}"),
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
Ok(ConValue::Empty)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +121,6 @@ impl Interpret for Use {
|
|||||||
|
|
||||||
impl Interpret for UseTree {
|
impl Interpret for UseTree {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
// TODO: raw-bind use items
|
|
||||||
type Bindings = HashMap<Sym, ConValue>;
|
type Bindings = HashMap<Sym, ConValue>;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -224,9 +137,9 @@ impl Interpret for UseTree {
|
|||||||
}
|
}
|
||||||
UseTree::Path(PathPart::Ident(name), tree) => {
|
UseTree::Path(PathPart::Ident(name), tree) => {
|
||||||
let Ok(ConValue::Module(m)) = env.get(*name) else {
|
let Ok(ConValue::Module(m)) = env.get(*name) else {
|
||||||
Err(Error::TypeError())?
|
Err(Error::TypeError)?
|
||||||
};
|
};
|
||||||
env.push_frame(name.to_ref(), *m);
|
env.push_frame(Interned::to_ref(name), *m);
|
||||||
let out = get_bindings(tree, env, bindings);
|
let out = get_bindings(tree, env, bindings);
|
||||||
env.pop_frame();
|
env.pop_frame();
|
||||||
return out;
|
return out;
|
||||||
@ -267,13 +180,12 @@ impl Interpret for UseTree {
|
|||||||
|
|
||||||
impl Interpret for Stmt {
|
impl Interpret for Stmt {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { span, kind, semi } = self;
|
let Self { extents: _, kind, semi } = self;
|
||||||
let out = match kind {
|
let out = match kind {
|
||||||
StmtKind::Empty => Ok(ConValue::Empty),
|
StmtKind::Empty => ConValue::Empty,
|
||||||
StmtKind::Item(stmt) => stmt.interpret(env),
|
StmtKind::Item(stmt) => stmt.interpret(env)?,
|
||||||
StmtKind::Expr(stmt) => stmt.interpret(env),
|
StmtKind::Expr(stmt) => stmt.interpret(env)?,
|
||||||
}
|
};
|
||||||
.map_err(|err| err.with_span(*span))?;
|
|
||||||
Ok(match semi {
|
Ok(match semi {
|
||||||
Semi::Terminated => ConValue::Empty,
|
Semi::Terminated => ConValue::Empty,
|
||||||
Semi::Unterminated => out,
|
Semi::Unterminated => out,
|
||||||
@ -284,8 +196,8 @@ impl Interpret for Stmt {
|
|||||||
impl Interpret for Expr {
|
impl Interpret for Expr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { span, kind } = self;
|
let Self { extents: _, kind } = self;
|
||||||
kind.interpret(env).map_err(|err| err.with_span(*span))
|
kind.interpret(env)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +205,6 @@ impl Interpret for ExprKind {
|
|||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
match self {
|
match self {
|
||||||
ExprKind::Empty => Ok(ConValue::Empty),
|
ExprKind::Empty => Ok(ConValue::Empty),
|
||||||
ExprKind::Closure(v) => v.interpret(env),
|
|
||||||
ExprKind::Quote(q) => q.interpret(env),
|
ExprKind::Quote(q) => q.interpret(env),
|
||||||
ExprKind::Let(v) => v.interpret(env),
|
ExprKind::Let(v) => v.interpret(env),
|
||||||
ExprKind::Match(v) => v.interpret(env),
|
ExprKind::Match(v) => v.interpret(env),
|
||||||
@ -318,19 +229,11 @@ impl Interpret for ExprKind {
|
|||||||
ExprKind::For(v) => v.interpret(env),
|
ExprKind::For(v) => v.interpret(env),
|
||||||
ExprKind::Break(v) => v.interpret(env),
|
ExprKind::Break(v) => v.interpret(env),
|
||||||
ExprKind::Return(v) => v.interpret(env),
|
ExprKind::Return(v) => v.interpret(env),
|
||||||
ExprKind::Continue => Err(Error::Continue()),
|
ExprKind::Continue => Err(Error::Continue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpret for Closure {
|
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
||||||
Ok(ConValue::Closure(
|
|
||||||
crate::closure::Closure::new(env, self).into(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Interpret for Quote {
|
impl Interpret for Quote {
|
||||||
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
||||||
// TODO: squoosh down into a ConValue?
|
// TODO: squoosh down into a ConValue?
|
||||||
@ -343,20 +246,23 @@ impl Interpret for Let {
|
|||||||
let Let { mutable: _, name, ty: _, init } = self;
|
let Let { mutable: _, name, ty: _, init } = self;
|
||||||
match init.as_ref().map(|i| i.interpret(env)).transpose()? {
|
match init.as_ref().map(|i| i.interpret(env)).transpose()? {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
if let Ok(sub) = pattern::substitution(name, value) {
|
for (path, value) in assignment::pattern_substitution(name, value)? {
|
||||||
for (name, value) in sub {
|
match path.parts.as_slice() {
|
||||||
env.insert(*name, Some(value));
|
[PathPart::Ident(name)] => env.insert(*name, Some(value)),
|
||||||
|
_ => eprintln!("Bad assignment: {path} = {value}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Ok(ConValue::Bool(true));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
for name in pattern::variables(name) {
|
for path in assignment::pattern_variables(name) {
|
||||||
env.insert(*name, None);
|
match path.parts.as_slice() {
|
||||||
|
[PathPart::Ident(name)] => env.insert(*name, None),
|
||||||
|
_ => eprintln!("Bad assignment: {path}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(ConValue::Bool(false))
|
}
|
||||||
|
Ok(ConValue::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,16 +270,19 @@ impl Interpret for Match {
|
|||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { scrutinee, arms } = self;
|
let Self { scrutinee, arms } = self;
|
||||||
let scrutinee = scrutinee.interpret(env)?;
|
let scrutinee = scrutinee.interpret(env)?;
|
||||||
for MatchArm(pat, expr) in arms {
|
'arm: for MatchArm(pat, expr) in arms {
|
||||||
if let Ok(substitution) = pattern::substitution(pat, scrutinee.clone()) {
|
if let Ok(substitution) = assignment::pattern_substitution(pat, scrutinee.clone()) {
|
||||||
let mut env = env.frame("match");
|
let mut env = env.frame("match");
|
||||||
for (name, value) in substitution {
|
for (path, value) in substitution {
|
||||||
|
let [PathPart::Ident(name)] = path.parts.as_slice() else {
|
||||||
|
continue 'arm;
|
||||||
|
};
|
||||||
env.insert(*name, Some(value));
|
env.insert(*name, Some(value));
|
||||||
}
|
}
|
||||||
return expr.interpret(&mut env);
|
return expr.interpret(&mut env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::MatchNonexhaustive())
|
Err(Error::MatchNonexhaustive)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,56 +292,165 @@ mod assignment {
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
type Namespace = HashMap<Sym, Option<ConValue>>;
|
type Namespace = HashMap<Sym, Option<ConValue>>;
|
||||||
|
|
||||||
|
/// Gets the path variables in the given Pattern
|
||||||
|
pub fn pattern_variables(pat: &Pattern) -> Vec<&Path> {
|
||||||
|
fn patvars<'p>(set: &mut Vec<&'p Path>, pat: &'p Pattern) {
|
||||||
|
match pat {
|
||||||
|
Pattern::Path(path) if path.is_sinkhole() => {}
|
||||||
|
Pattern::Path(path) => set.push(path),
|
||||||
|
Pattern::Literal(_) => {}
|
||||||
|
Pattern::Ref(_, pattern) => patvars(set, pattern),
|
||||||
|
Pattern::Tuple(patterns) | Pattern::Array(patterns) => {
|
||||||
|
patterns.iter().for_each(|pat| patvars(set, pat))
|
||||||
|
}
|
||||||
|
Pattern::Struct(_path, items) => {
|
||||||
|
items.iter().for_each(|(name, pat)| match pat {
|
||||||
|
Some(pat) => patvars(set, pat),
|
||||||
|
None => set.push(name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut set = Vec::new();
|
||||||
|
patvars(&mut set, pat);
|
||||||
|
set
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Appends a substitution to the provided table
|
||||||
|
pub fn append_sub<'pat>(
|
||||||
|
env: &mut HashMap<&'pat Path, ConValue>,
|
||||||
|
pat: &'pat Pattern,
|
||||||
|
value: ConValue,
|
||||||
|
) -> IResult<()> {
|
||||||
|
match pat {
|
||||||
|
Pattern::Path(path) if path.is_sinkhole() => Ok(()),
|
||||||
|
Pattern::Path(path) => {
|
||||||
|
env.insert(path, value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern::Literal(literal) => match (literal, value) {
|
||||||
|
(Literal::Bool(a), ConValue::Bool(b)) => *a == b,
|
||||||
|
(Literal::Char(a), ConValue::Char(b)) => *a == b,
|
||||||
|
(Literal::Int(a), ConValue::Int(b)) => *a as isize == b,
|
||||||
|
(Literal::Float(a), ConValue::Float(b)) => f64::from_bits(*a) == b,
|
||||||
|
(Literal::String(a), ConValue::String(b)) => *a == *b,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
.then_some(())
|
||||||
|
.ok_or(Error::NotAssignable),
|
||||||
|
|
||||||
|
Pattern::Ref(_, pattern) => match value {
|
||||||
|
ConValue::Ref(value) => append_sub(env, pattern, Rc::unwrap_or_clone(value)),
|
||||||
|
_ => Err(Error::NotAssignable),
|
||||||
|
},
|
||||||
|
|
||||||
|
Pattern::Tuple(patterns) => match value {
|
||||||
|
ConValue::Tuple(values) => {
|
||||||
|
if patterns.len() != values.len() {
|
||||||
|
return Err(Error::OobIndex(patterns.len(), values.len()));
|
||||||
|
};
|
||||||
|
for (pat, value) in patterns.iter().zip(Vec::from(values).into_iter()) {
|
||||||
|
append_sub(env, pat, value)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::NotAssignable),
|
||||||
|
},
|
||||||
|
|
||||||
|
Pattern::Array(patterns) => match value {
|
||||||
|
ConValue::Array(values) => {
|
||||||
|
if patterns.len() != values.len() {
|
||||||
|
return Err(Error::OobIndex(patterns.len(), values.len()));
|
||||||
|
};
|
||||||
|
for (pat, value) in patterns.iter().zip(Vec::from(values).into_iter()) {
|
||||||
|
append_sub(env, pat, value)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::NotAssignable),
|
||||||
|
},
|
||||||
|
|
||||||
|
Pattern::Struct(_path, patterns) => {
|
||||||
|
let ConValue::Struct(parts) = value else {
|
||||||
|
return Err(Error::TypeError);
|
||||||
|
};
|
||||||
|
let (_, mut values) = *parts;
|
||||||
|
if values.len() != patterns.len() {
|
||||||
|
return Err(Error::TypeError);
|
||||||
|
}
|
||||||
|
for (name, pat) in patterns {
|
||||||
|
let [.., PathPart::Ident(index)] = name.parts.as_slice() else {
|
||||||
|
Err(Error::TypeError)?
|
||||||
|
};
|
||||||
|
let value = values.remove(index).ok_or(Error::TypeError)?;
|
||||||
|
match pat {
|
||||||
|
Some(pat) => append_sub(env, pat, value)?,
|
||||||
|
None => {
|
||||||
|
env.insert(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a substitution from a pattern and a value
|
||||||
|
pub fn pattern_substitution(
|
||||||
|
pat: &Pattern,
|
||||||
|
value: ConValue,
|
||||||
|
) -> IResult<HashMap<&Path, ConValue>> {
|
||||||
|
let mut substitution = HashMap::new();
|
||||||
|
append_sub(&mut substitution, pat, value)?;
|
||||||
|
Ok(substitution)
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn pat_assign(env: &mut Environment, pat: &Pattern, value: ConValue) -> IResult<()> {
|
pub(super) fn pat_assign(env: &mut Environment, pat: &Pattern, value: ConValue) -> IResult<()> {
|
||||||
for (name, value) in
|
let mut substitution = HashMap::new();
|
||||||
pattern::substitution(pat, value).map_err(|_| Error::PatFailed(pat.clone().into()))?
|
append_sub(&mut substitution, pat, value)
|
||||||
{
|
.map_err(|_| Error::PatFailed(pat.clone().into()))?;
|
||||||
match env.get_mut(*name)? {
|
for (path, value) in substitution {
|
||||||
&mut Some(ConValue::Ref(id)) => {
|
assign_path(env, path, value)?;
|
||||||
*(env.get_id_mut(id).ok_or(Error::StackOverflow(id))?) = Some(value);
|
|
||||||
}
|
|
||||||
other => *other = Some(value),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn assign(env: &mut Environment, pat: &Expr, value: ConValue) -> IResult<()> {
|
pub(super) fn assign(env: &mut Environment, pat: &ExprKind, value: ConValue) -> IResult<()> {
|
||||||
if let Ok(pat) = Pattern::try_from(pat.clone()) {
|
if let Ok(pat) = Pattern::try_from(pat.clone()) {
|
||||||
return pat_assign(env, &pat, value);
|
return pat_assign(env, &pat, value);
|
||||||
}
|
}
|
||||||
match &pat.kind {
|
match pat {
|
||||||
ExprKind::Member(member) => *addrof_member(env, member)? = value,
|
ExprKind::Member(member) => *addrof_member(env, member)? = value,
|
||||||
ExprKind::Index(index) => *addrof_index(env, index)? = value,
|
ExprKind::Index(index) => *addrof_index(env, index)? = value,
|
||||||
ExprKind::Path(path) => *addrof_path(env, &path.parts)? = Some(value),
|
_ => Err(Error::NotAssignable)?,
|
||||||
ExprKind::Unary(Unary { kind: UnaryKind::Deref, tail }) => match addrof(env, tail)? {
|
|
||||||
&mut ConValue::Ref(r) => {
|
|
||||||
*env.get_id_mut(r).ok_or(Error::StackOverflow(r))? = Some(value)
|
|
||||||
}
|
|
||||||
_ => Err(Error::NotAssignable())?,
|
|
||||||
},
|
|
||||||
_ => Err(Error::NotAssignable())?,
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn addrof<'e>(env: &'e mut Environment, pat: &Expr) -> IResult<&'e mut ConValue> {
|
fn assign_path(env: &mut Environment, path: &Path, value: ConValue) -> IResult<()> {
|
||||||
match &pat.kind {
|
let Ok(addr) = addrof_path(env, &path.parts) else {
|
||||||
|
eprintln!("Cannot assign {value} to path {path}");
|
||||||
|
return Err(Error::NotAssignable);
|
||||||
|
};
|
||||||
|
*addr = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn addrof<'e>(
|
||||||
|
env: &'e mut Environment,
|
||||||
|
pat: &ExprKind,
|
||||||
|
) -> IResult<&'e mut ConValue> {
|
||||||
|
match pat {
|
||||||
ExprKind::Path(path) => addrof_path(env, &path.parts)?
|
ExprKind::Path(path) => addrof_path(env, &path.parts)?
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.ok_or(Error::NotInitialized("".into())),
|
.ok_or(Error::NotInitialized("".into())),
|
||||||
ExprKind::Member(member) => addrof_member(env, member),
|
ExprKind::Member(member) => addrof_member(env, member),
|
||||||
ExprKind::Index(index) => addrof_index(env, index),
|
ExprKind::Index(index) => addrof_index(env, index),
|
||||||
ExprKind::Group(Group { expr }) => addrof(env, expr),
|
ExprKind::Group(Group { expr }) => addrof(env, expr),
|
||||||
ExprKind::Unary(Unary { kind: UnaryKind::Deref, tail }) => match *addrof(env, tail)? {
|
ExprKind::AddrOf(AddrOf { mutable: Mutability::Mut, expr }) => addrof(env, expr),
|
||||||
ConValue::Ref(place) => env
|
_ => Err(Error::TypeError),
|
||||||
.get_id_mut(place)
|
|
||||||
.ok_or(Error::NotIndexable())?
|
|
||||||
.as_mut()
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
_ => Err(Error::TypeError()),
|
|
||||||
},
|
|
||||||
_ => Err(Error::TypeError()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,21 +461,30 @@ mod assignment {
|
|||||||
match path {
|
match path {
|
||||||
[PathPart::Ident(name)] => env.get_mut(*name),
|
[PathPart::Ident(name)] => env.get_mut(*name),
|
||||||
[PathPart::Ident(name), rest @ ..] => match env.get_mut(*name)? {
|
[PathPart::Ident(name), rest @ ..] => match env.get_mut(*name)? {
|
||||||
Some(ConValue::Module(env)) => project_path_in_namespace(env, rest),
|
Some(ConValue::Module(env)) => addrof_path_within_namespace(env, rest),
|
||||||
_ => Err(Error::NotIndexable()),
|
_ => Err(Error::NotIndexable),
|
||||||
},
|
},
|
||||||
_ => Err(Error::NotAssignable()),
|
_ => Err(Error::NotAssignable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addrof_member<'e>(
|
fn addrof_member<'e>(env: &'e mut Environment, member: &Member) -> IResult<&'e mut ConValue> {
|
||||||
env: &'e mut Environment,
|
|
||||||
member: &Member,
|
|
||||||
) -> IResult<&'e mut ConValue> {
|
|
||||||
let Member { head, kind } = member;
|
let Member { head, kind } = member;
|
||||||
|
let ExprKind::Path(path) = head.as_ref() else {
|
||||||
let head = addrof(env, head)?;
|
return Err(Error::TypeError);
|
||||||
project_memberkind(head, kind)
|
};
|
||||||
|
let slot = addrof_path(env, &path.parts)?
|
||||||
|
.as_mut()
|
||||||
|
.ok_or(Error::NotAssignable)?;
|
||||||
|
Ok(match (slot, kind) {
|
||||||
|
(ConValue::Struct(s), MemberKind::Struct(id)) => {
|
||||||
|
s.1.get_mut(id).ok_or(Error::NotDefined(*id))?
|
||||||
|
}
|
||||||
|
(ConValue::Tuple(t), MemberKind::Tuple(Literal::Int(id))) => t
|
||||||
|
.get_mut(*id as usize)
|
||||||
|
.ok_or_else(|| Error::NotDefined(id.to_string().into()))?,
|
||||||
|
_ => Err(Error::TypeError)?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addrof_index<'e>(env: &'e mut Environment, index: &Index) -> IResult<&'e mut ConValue> {
|
fn addrof_index<'e>(env: &'e mut Environment, index: &Index) -> IResult<&'e mut ConValue> {
|
||||||
@ -466,66 +493,34 @@ mod assignment {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|index| index.interpret(env))
|
.map(|index| index.interpret(env))
|
||||||
.collect::<IResult<Vec<_>>>()?;
|
.collect::<IResult<Vec<_>>>()?;
|
||||||
|
|
||||||
let mut head = addrof(env, head)?;
|
let mut head = addrof(env, head)?;
|
||||||
for index in indices {
|
for index in indices {
|
||||||
head = project_index(head, &index)?;
|
head = match (head, index) {
|
||||||
|
(ConValue::Array(a), ConValue::Int(i)) => {
|
||||||
|
let a_len = a.len();
|
||||||
|
a.get_mut(i as usize)
|
||||||
|
.ok_or(Error::OobIndex(i as usize, a_len))?
|
||||||
|
}
|
||||||
|
_ => Err(Error::NotIndexable)?,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(head)
|
Ok(head)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs member-access "projection" from a ConValue to a particular element
|
pub fn addrof_path_within_namespace<'e>(
|
||||||
pub fn project_memberkind<'v>(
|
|
||||||
value: &'v mut ConValue,
|
|
||||||
kind: &MemberKind,
|
|
||||||
) -> IResult<&'v mut ConValue> {
|
|
||||||
match (value, kind) {
|
|
||||||
(ConValue::Struct(s), MemberKind::Struct(id)) => {
|
|
||||||
s.1.get_mut(id).ok_or(Error::NotDefined(*id))
|
|
||||||
}
|
|
||||||
(ConValue::TupleStruct(s), MemberKind::Tuple(Literal::Int(id))) => {
|
|
||||||
let len = s.1.len();
|
|
||||||
s.1.get_mut(*id as usize)
|
|
||||||
.ok_or(Error::OobIndex(*id as _, len))
|
|
||||||
}
|
|
||||||
(ConValue::Tuple(t), MemberKind::Tuple(Literal::Int(id))) => {
|
|
||||||
let len = t.len();
|
|
||||||
t.get_mut(*id as usize)
|
|
||||||
.ok_or(Error::OobIndex(*id as _, len))
|
|
||||||
}
|
|
||||||
_ => Err(Error::TypeError()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs index "projection" from a ConValue to a particular element
|
|
||||||
pub fn project_index<'v>(
|
|
||||||
value: &'v mut ConValue,
|
|
||||||
index: &ConValue,
|
|
||||||
) -> IResult<&'v mut ConValue> {
|
|
||||||
match (value, index) {
|
|
||||||
(ConValue::Array(a), ConValue::Int(i)) => {
|
|
||||||
let a_len = a.len();
|
|
||||||
a.get_mut(*i as usize)
|
|
||||||
.ok_or(Error::OobIndex(*i as usize, a_len))
|
|
||||||
}
|
|
||||||
(ConValue::Slice(_, _), _) => Err(Error::TypeError()),
|
|
||||||
_ => Err(Error::NotIndexable()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn project_path_in_namespace<'e>(
|
|
||||||
env: &'e mut Namespace,
|
env: &'e mut Namespace,
|
||||||
path: &[PathPart],
|
path: &[PathPart],
|
||||||
) -> IResult<&'e mut Option<ConValue>> {
|
) -> IResult<&'e mut Option<ConValue>> {
|
||||||
match path {
|
match path {
|
||||||
[] => Err(Error::NotAssignable()),
|
[] => Err(Error::NotAssignable),
|
||||||
[PathPart::Ident(name)] => env.get_mut(name).ok_or(Error::NotDefined(*name)),
|
[PathPart::Ident(name)] => env.get_mut(name).ok_or(Error::NotDefined(*name)),
|
||||||
[PathPart::Ident(name), rest @ ..] => {
|
[PathPart::Ident(name), rest @ ..] => {
|
||||||
match env.get_mut(name).ok_or(Error::NotDefined(*name))? {
|
match env.get_mut(name).ok_or(Error::NotDefined(*name))? {
|
||||||
Some(ConValue::Module(env)) => project_path_in_namespace(env, rest),
|
Some(ConValue::Module(env)) => addrof_path_within_namespace(env, rest),
|
||||||
_ => Err(Error::NotIndexable()),
|
_ => Err(Error::NotIndexable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[PathPart::SelfKw, rest @ ..] => addrof_path_within_namespace(env, rest),
|
||||||
[PathPart::SelfTy, ..] => todo!("calc_address for `Self`"),
|
[PathPart::SelfTy, ..] => todo!("calc_address for `Self`"),
|
||||||
[PathPart::SuperKw, ..] => todo!("calc_address for `super`"),
|
[PathPart::SuperKw, ..] => todo!("calc_address for `super`"),
|
||||||
}
|
}
|
||||||
@ -571,6 +566,8 @@ impl Interpret for Binary {
|
|||||||
let (head, tail) = parts.borrow();
|
let (head, tail) = parts.borrow();
|
||||||
|
|
||||||
let head = head.interpret(env)?;
|
let head = head.interpret(env)?;
|
||||||
|
|
||||||
|
// Short-circuiting ops
|
||||||
match kind {
|
match kind {
|
||||||
BinaryKind::LogAnd => {
|
BinaryKind::LogAnd => {
|
||||||
return if head.truthy()? {
|
return if head.truthy()? {
|
||||||
@ -593,7 +590,6 @@ impl Interpret for Binary {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tail = tail.interpret(env)?;
|
let tail = tail.interpret(env)?;
|
||||||
match kind {
|
match kind {
|
||||||
BinaryKind::Lt => head.lt(&tail),
|
BinaryKind::Lt => head.lt(&tail),
|
||||||
@ -602,8 +598,8 @@ impl Interpret for Binary {
|
|||||||
BinaryKind::NotEq => head.neq(&tail),
|
BinaryKind::NotEq => head.neq(&tail),
|
||||||
BinaryKind::GtEq => head.gt_eq(&tail),
|
BinaryKind::GtEq => head.gt_eq(&tail),
|
||||||
BinaryKind::Gt => head.gt(&tail),
|
BinaryKind::Gt => head.gt(&tail),
|
||||||
BinaryKind::RangeExc => env.call("RangeExc".into(), &[head, tail]),
|
BinaryKind::RangeExc => head.range_exc(tail),
|
||||||
BinaryKind::RangeInc => env.call("RangeInc".into(), &[head, tail]),
|
BinaryKind::RangeInc => head.range_inc(tail),
|
||||||
BinaryKind::BitAnd => head & tail,
|
BinaryKind::BitAnd => head & tail,
|
||||||
BinaryKind::BitOr => head | tail,
|
BinaryKind::BitOr => head | tail,
|
||||||
BinaryKind::BitXor => head ^ tail,
|
BinaryKind::BitXor => head ^ tail,
|
||||||
@ -617,10 +613,40 @@ impl Interpret for Binary {
|
|||||||
BinaryKind::Call => match tail {
|
BinaryKind::Call => match tail {
|
||||||
ConValue::Empty => head.call(env, &[]),
|
ConValue::Empty => head.call(env, &[]),
|
||||||
ConValue::Tuple(args) => head.call(env, &args),
|
ConValue::Tuple(args) => head.call(env, &args),
|
||||||
_ => Err(Error::TypeError()),
|
_ => Err(Error::TypeError),
|
||||||
},
|
},
|
||||||
_ => Ok(head),
|
_ => Ok(head),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// // Temporarily disabled, to avoid function dispatch overhead while I screw around
|
||||||
|
// // Not like it helped much in the first place!
|
||||||
|
// match kind {
|
||||||
|
// BinaryKind::Mul => env.call("mul", &[head, tail]),
|
||||||
|
// BinaryKind::Div => env.call("div", &[head, tail]),
|
||||||
|
// BinaryKind::Rem => env.call("rem", &[head, tail]),
|
||||||
|
// BinaryKind::Add => env.call("add", &[head, tail]),
|
||||||
|
// BinaryKind::Sub => env.call("sub", &[head, tail]),
|
||||||
|
// BinaryKind::Shl => env.call("shl", &[head, tail]),
|
||||||
|
// BinaryKind::Shr => env.call("shr", &[head, tail]),
|
||||||
|
// BinaryKind::BitAnd => env.call("and", &[head, tail]),
|
||||||
|
// BinaryKind::BitOr => env.call("or", &[head, tail]),
|
||||||
|
// BinaryKind::BitXor => env.call("xor", &[head, tail]),
|
||||||
|
// BinaryKind::RangeExc => env.call("range_exc", &[head, tail]),
|
||||||
|
// BinaryKind::RangeInc => env.call("range_inc", &[head, tail]),
|
||||||
|
// BinaryKind::Lt => env.call("lt", &[head, tail]),
|
||||||
|
// BinaryKind::LtEq => env.call("lt_eq", &[head, tail]),
|
||||||
|
// BinaryKind::Equal => env.call("eq", &[head, tail]),
|
||||||
|
// BinaryKind::NotEq => env.call("neq", &[head, tail]),
|
||||||
|
// BinaryKind::GtEq => env.call("gt_eq", &[head, tail]),
|
||||||
|
// BinaryKind::Gt => env.call("gt", &[head, tail]),
|
||||||
|
// BinaryKind::Dot => todo!("search within a type's namespace!"),
|
||||||
|
// BinaryKind::Call => match tail {
|
||||||
|
// ConValue::Empty => head.call(env, &[]),
|
||||||
|
// ConValue::Tuple(args) => head.call(env, &args),
|
||||||
|
// _ => Err(Error::TypeError),
|
||||||
|
// },
|
||||||
|
// _ => Ok(head),
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,8 +656,8 @@ impl Interpret for Unary {
|
|||||||
match kind {
|
match kind {
|
||||||
UnaryKind::Loop => loop {
|
UnaryKind::Loop => loop {
|
||||||
match tail.interpret(env) {
|
match tail.interpret(env) {
|
||||||
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
|
Err(Error::Break(value)) => return Ok(value),
|
||||||
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
|
Err(Error::Continue) => continue,
|
||||||
e => e?,
|
e => e?,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -647,14 +673,6 @@ impl Interpret for Unary {
|
|||||||
let operand = tail.interpret(env)?;
|
let operand = tail.interpret(env)?;
|
||||||
env.call("not".into(), &[operand])
|
env.call("not".into(), &[operand])
|
||||||
}
|
}
|
||||||
UnaryKind::RangeExc => {
|
|
||||||
let operand = tail.interpret(env)?;
|
|
||||||
env.call("RangeTo".into(), &[operand])
|
|
||||||
}
|
|
||||||
UnaryKind::RangeInc => {
|
|
||||||
let operand = tail.interpret(env)?;
|
|
||||||
env.call("RangeToInc".into(), &[operand])
|
|
||||||
}
|
|
||||||
UnaryKind::At => {
|
UnaryKind::At => {
|
||||||
let operand = tail.interpret(env)?;
|
let operand = tail.interpret(env)?;
|
||||||
println!("{operand}");
|
println!("{operand}");
|
||||||
@ -665,24 +683,17 @@ impl Interpret for Unary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cast(env: &Environment, value: ConValue, ty: Sym) -> IResult<ConValue> {
|
fn cast(value: ConValue, ty: Sym) -> IResult<ConValue> {
|
||||||
let value = match value {
|
let value = match value {
|
||||||
ConValue::Empty => 0,
|
ConValue::Empty => 0,
|
||||||
ConValue::Int(i) => i as _,
|
ConValue::Int(i) => i as _,
|
||||||
ConValue::Bool(b) => b as _,
|
ConValue::Bool(b) => b as _,
|
||||||
ConValue::Char(c) => c as _,
|
ConValue::Char(c) => c as _,
|
||||||
ConValue::Ref(v) => {
|
ConValue::Ref(v) => return cast((*v).clone(), ty),
|
||||||
return cast(
|
|
||||||
env,
|
|
||||||
env.get_id(v).cloned().ok_or(Error::StackUnderflow())?,
|
|
||||||
ty,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// TODO: This, better
|
// TODO: This, better
|
||||||
ConValue::Float(_) if ty.starts_with('f') => return Ok(value),
|
ConValue::Float(_) if ty.starts_with('f') => return Ok(value),
|
||||||
ConValue::Float(f) => f as _,
|
ConValue::Float(f) => f as _,
|
||||||
_ if (*ty).eq("str") => return Ok(ConValue::String(format!("{value}").into())),
|
_ => Err(Error::TypeError)?,
|
||||||
_ => Err(Error::TypeError())?,
|
|
||||||
};
|
};
|
||||||
Ok(match &*ty {
|
Ok(match &*ty {
|
||||||
"u8" => ConValue::Int(value as u8 as _),
|
"u8" => ConValue::Int(value as u8 as _),
|
||||||
@ -709,11 +720,11 @@ impl Interpret for Cast {
|
|||||||
return Ok(ConValue::Empty);
|
return Ok(ConValue::Empty);
|
||||||
};
|
};
|
||||||
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
||||||
Err(Error::TypeError())?
|
Err(Error::TypeError)?
|
||||||
};
|
};
|
||||||
match parts.as_slice() {
|
match parts.as_slice() {
|
||||||
[PathPart::Ident(ty)] => cast(env, value, *ty),
|
[PathPart::Ident(ty)] => cast(value, *ty),
|
||||||
_ => Err(Error::TypeError()),
|
_ => Err(Error::TypeError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -721,22 +732,16 @@ impl Interpret for Cast {
|
|||||||
impl Interpret for Member {
|
impl Interpret for Member {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Member { head, kind } = self;
|
let Member { head, kind } = self;
|
||||||
// Attempt member access projection (fast path)
|
let head = head.interpret(env)?;
|
||||||
if let Ok(member) = assignment::addrof_member(env, self) {
|
match (head, kind) {
|
||||||
return Ok(member.clone());
|
(ConValue::Tuple(v), MemberKind::Tuple(Literal::Int(id))) => v
|
||||||
|
.get(*id as usize)
|
||||||
|
.cloned()
|
||||||
|
.ok_or(Error::OobIndex(*id as usize, v.len())),
|
||||||
|
(ConValue::Struct(parts), MemberKind::Struct(name)) => {
|
||||||
|
parts.1.get(name).cloned().ok_or(Error::NotDefined(*name))
|
||||||
}
|
}
|
||||||
// Evaluate if this can be Self'd
|
(ConValue::Struct(parts), MemberKind::Call(name, args)) => {
|
||||||
let value = match (&head.kind, kind) {
|
|
||||||
(ExprKind::Path(p), MemberKind::Call(..)) => {
|
|
||||||
p.as_sym().map(|name| Ok(ConValue::Ref(env.id_of(name)?))) // "borrow" it
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
// Perform alternate member access
|
|
||||||
match (value.unwrap_or_else(|| head.interpret(env))?, kind) {
|
|
||||||
(ConValue::Struct(parts), MemberKind::Call(name, args))
|
|
||||||
if parts.1.contains_key(name) =>
|
|
||||||
{
|
|
||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
for arg in &args.exprs {
|
for arg in &args.exprs {
|
||||||
values.push(arg.interpret(env)?);
|
values.push(arg.interpret(env)?);
|
||||||
@ -754,7 +759,7 @@ impl Interpret for Member {
|
|||||||
}
|
}
|
||||||
env.call(*name, &values)
|
env.call(*name, &values)
|
||||||
}
|
}
|
||||||
(mut head, kind) => assignment::project_memberkind(&mut head, kind).cloned(),
|
_ => Err(Error::TypeError)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -763,7 +768,7 @@ impl Interpret for Index {
|
|||||||
let Self { head, indices } = self;
|
let Self { head, indices } = self;
|
||||||
let mut head = head.interpret(env)?;
|
let mut head = head.interpret(env)?;
|
||||||
for index in indices {
|
for index in indices {
|
||||||
head = head.index(&index.interpret(env)?, env)?;
|
head = head.index(&index.interpret(env)?)?;
|
||||||
}
|
}
|
||||||
Ok(head)
|
Ok(head)
|
||||||
}
|
}
|
||||||
@ -773,10 +778,9 @@ impl Interpret for Structor {
|
|||||||
let Self { to: Path { absolute: _, parts }, init } = self;
|
let Self { to: Path { absolute: _, parts }, init } = self;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
// Look up struct/enum-struct definition
|
|
||||||
|
|
||||||
let name = match parts.last() {
|
let name = match parts.last() {
|
||||||
Some(PathPart::Ident(name)) => *name,
|
Some(PathPart::Ident(name)) => *name,
|
||||||
|
Some(PathPart::SelfKw) => "self".into(),
|
||||||
Some(PathPart::SelfTy) => "Self".into(),
|
Some(PathPart::SelfTy) => "Self".into(),
|
||||||
Some(PathPart::SuperKw) => "super".into(),
|
Some(PathPart::SuperKw) => "super".into(),
|
||||||
None => "".into(),
|
None => "".into(),
|
||||||
@ -828,24 +832,21 @@ impl Interpret for Array {
|
|||||||
impl Interpret for ArrayRep {
|
impl Interpret for ArrayRep {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { value, repeat } = self;
|
let Self { value, repeat } = self;
|
||||||
|
let repeat = match repeat.interpret(env)? {
|
||||||
|
ConValue::Int(v) => v,
|
||||||
|
_ => Err(Error::TypeError)?,
|
||||||
|
};
|
||||||
let value = value.interpret(env)?;
|
let value = value.interpret(env)?;
|
||||||
Ok(ConValue::Array(vec![value; *repeat].into()))
|
Ok(ConValue::Array(vec![value; repeat as usize].into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Interpret for AddrOf {
|
impl Interpret for AddrOf {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { mutable: _, expr } = self;
|
let Self { mutable: _, expr } = self;
|
||||||
match &expr.kind {
|
match expr.as_ref() {
|
||||||
ExprKind::Index(_) => todo!("AddrOf array index"),
|
ExprKind::Index(_) => todo!("AddrOf array index"),
|
||||||
ExprKind::Path(Path { parts, .. }) => match parts.as_slice() {
|
ExprKind::Path(_) => todo!("Path traversal in addrof"),
|
||||||
[PathPart::Ident(name)] => Ok(ConValue::Ref(env.id_of(*name)?)),
|
_ => Ok(ConValue::Ref(Rc::new(expr.interpret(env)?))),
|
||||||
_ => todo!("Path traversal in AddrOf(\"{self}\")"),
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let value = expr.interpret(env)?;
|
|
||||||
let temp = env.stack_alloc(value)?;
|
|
||||||
Ok(ConValue::Ref(env::Place::Local(temp)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -886,8 +887,8 @@ impl Interpret for While {
|
|||||||
loop {
|
loop {
|
||||||
if cond.interpret(env)?.truthy()? {
|
if cond.interpret(env)?.truthy()? {
|
||||||
match pass.interpret(env) {
|
match pass.interpret(env) {
|
||||||
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
|
Err(Error::Break(value)) => return Ok(value),
|
||||||
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
|
Err(Error::Continue) => continue,
|
||||||
e => e?,
|
e => e?,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@ -908,39 +909,24 @@ impl Interpret for If {
|
|||||||
}
|
}
|
||||||
impl Interpret for For {
|
impl Interpret for For {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Self { bind, cond, pass, fail } = self;
|
let Self { bind: name, cond, pass, fail } = self;
|
||||||
let cond = cond.interpret(env)?;
|
let cond = cond.interpret(env)?;
|
||||||
// TODO: A better iterator model
|
// TODO: A better iterator model
|
||||||
let mut bounds: Box<dyn Iterator<Item = ConValue>> = match &cond {
|
let mut bounds: Box<dyn Iterator<Item = ConValue>> = match &cond {
|
||||||
ConValue::TupleStruct(inner) => match &**inner {
|
&ConValue::RangeExc(a, b) => Box::new((a..b).map(ConValue::Int)),
|
||||||
("RangeExc", values) => match **values {
|
&ConValue::RangeInc(a, b) => Box::new((a..=b).map(ConValue::Int)),
|
||||||
[ConValue::Int(from), ConValue::Int(to)] => {
|
|
||||||
Box::new((from..to).map(ConValue::Int))
|
|
||||||
}
|
|
||||||
_ => Err(Error::NotIterable())?,
|
|
||||||
},
|
|
||||||
("RangeInc", values) => match **values {
|
|
||||||
[ConValue::Int(from), ConValue::Int(to)] => {
|
|
||||||
Box::new((from..=to).map(ConValue::Int))
|
|
||||||
}
|
|
||||||
_ => Err(Error::NotIterable())?,
|
|
||||||
},
|
|
||||||
_ => Err(Error::NotIterable())?,
|
|
||||||
},
|
|
||||||
ConValue::Array(a) => Box::new(a.iter().cloned()),
|
ConValue::Array(a) => Box::new(a.iter().cloned()),
|
||||||
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
|
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
|
||||||
_ => Err(Error::TypeError())?,
|
_ => Err(Error::TypeError)?,
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
let mut env = env.frame("loop variable");
|
let mut env = env.frame("loop variable");
|
||||||
if let Some(value) = bounds.next() {
|
if let Some(loop_var) = bounds.next() {
|
||||||
for (name, value) in pattern::substitution(bind, value)? {
|
env.insert(*name, Some(loop_var));
|
||||||
env.insert(*name, Some(value));
|
|
||||||
}
|
|
||||||
match pass.interpret(&mut env) {
|
match pass.interpret(&mut env) {
|
||||||
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
|
Err(Error::Break(value)) => return Ok(value),
|
||||||
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
|
Err(Error::Continue) => continue,
|
||||||
e => e?,
|
result => result?,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
break fail.interpret(&mut env);
|
break fail.interpret(&mut env);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
use cl_ast::Sym;
|
use cl_ast::Sym;
|
||||||
use convalue::ConValue;
|
use convalue::ConValue;
|
||||||
use env::Environment;
|
use env::Environment;
|
||||||
use error::{Error, ErrorKind, IResult};
|
use error::{Error, IResult};
|
||||||
use interpret::Interpret;
|
use interpret::Interpret;
|
||||||
|
|
||||||
/// Callable types can be called from within a Conlang program
|
/// Callable types can be called from within a Conlang program
|
||||||
@ -23,12 +23,8 @@ pub mod interpret;
|
|||||||
|
|
||||||
pub mod function;
|
pub mod function;
|
||||||
|
|
||||||
pub mod closure;
|
|
||||||
|
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
|
|
||||||
pub mod pattern;
|
|
||||||
|
|
||||||
pub mod env;
|
pub mod env;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
@ -1,258 +0,0 @@
|
|||||||
//! Unification algorithm for cl-ast [Pattern]s and [ConValue]s
|
|
||||||
//!
|
|
||||||
//! [`variables()`] returns a flat list of symbols that are bound by a given pattern
|
|
||||||
//! [`substitution()`] unifies a ConValue with a pattern, and produces a list of bound names
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
convalue::ConValue,
|
|
||||||
error::{Error, IResult},
|
|
||||||
};
|
|
||||||
use cl_ast::{Literal, Pattern, Sym};
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
|
||||||
|
|
||||||
/// Gets the path variables in the given Pattern
|
|
||||||
pub fn variables(pat: &Pattern) -> Vec<&Sym> {
|
|
||||||
fn patvars<'p>(set: &mut Vec<&'p Sym>, pat: &'p Pattern) {
|
|
||||||
match pat {
|
|
||||||
Pattern::Name(name) if name.to_ref() == "_" => {}
|
|
||||||
Pattern::Name(name) => set.push(name),
|
|
||||||
Pattern::Path(_) => {}
|
|
||||||
Pattern::Literal(_) => {}
|
|
||||||
Pattern::Rest(Some(pattern)) => patvars(set, pattern),
|
|
||||||
Pattern::Rest(None) => {}
|
|
||||||
Pattern::Ref(_, pattern) => patvars(set, pattern),
|
|
||||||
Pattern::RangeExc(_, _) => {}
|
|
||||||
Pattern::RangeInc(_, _) => {}
|
|
||||||
Pattern::Tuple(patterns) | Pattern::Array(patterns) => {
|
|
||||||
patterns.iter().for_each(|pat| patvars(set, pat))
|
|
||||||
}
|
|
||||||
Pattern::Struct(_path, items) => {
|
|
||||||
items.iter().for_each(|(name, pat)| match pat {
|
|
||||||
Some(pat) => patvars(set, pat),
|
|
||||||
None => set.push(name),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Pattern::TupleStruct(_path, items) => {
|
|
||||||
items.iter().for_each(|pat| patvars(set, pat));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut set = Vec::new();
|
|
||||||
patvars(&mut set, pat);
|
|
||||||
set
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rest_binding<'pat>(
|
|
||||||
sub: &mut HashMap<&'pat Sym, ConValue>,
|
|
||||||
mut patterns: &'pat [Pattern],
|
|
||||||
mut values: VecDeque<ConValue>,
|
|
||||||
) -> IResult<Option<(&'pat Pattern, VecDeque<ConValue>)>> {
|
|
||||||
// Bind the head of the list
|
|
||||||
while let [pattern, tail @ ..] = patterns {
|
|
||||||
if matches!(pattern, Pattern::Rest(_)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let value = values
|
|
||||||
.pop_front()
|
|
||||||
.ok_or_else(|| Error::PatFailed(Box::new(pattern.clone())))?;
|
|
||||||
append_sub(sub, pattern, value)?;
|
|
||||||
patterns = tail;
|
|
||||||
}
|
|
||||||
// Bind the tail of the list
|
|
||||||
while let [head @ .., pattern] = patterns {
|
|
||||||
if matches!(pattern, Pattern::Rest(_)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let value = values
|
|
||||||
.pop_back()
|
|
||||||
.ok_or_else(|| Error::PatFailed(Box::new(pattern.clone())))?;
|
|
||||||
append_sub(sub, pattern, value)?;
|
|
||||||
patterns = head;
|
|
||||||
}
|
|
||||||
// Bind the ..rest of the list
|
|
||||||
match patterns {
|
|
||||||
[] | [Pattern::Rest(None)] => Ok(None),
|
|
||||||
[Pattern::Rest(Some(pattern))] => Ok(Some((pattern.as_ref(), values))),
|
|
||||||
_ => Err(Error::PatFailed(Box::new(Pattern::Array(patterns.into())))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Appends a substitution to the provided table
|
|
||||||
pub fn append_sub<'pat>(
|
|
||||||
sub: &mut HashMap<&'pat Sym, ConValue>,
|
|
||||||
pat: &'pat Pattern,
|
|
||||||
value: ConValue,
|
|
||||||
) -> IResult<()> {
|
|
||||||
match (pat, value) {
|
|
||||||
(Pattern::Literal(Literal::Bool(a)), ConValue::Bool(b)) => {
|
|
||||||
(*a == b).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(Literal::Char(a)), ConValue::Char(b)) => {
|
|
||||||
(*a == b).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(Literal::Float(a)), ConValue::Float(b)) => (f64::from_bits(*a) == b)
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
(Pattern::Literal(Literal::Int(a)), ConValue::Int(b)) => {
|
|
||||||
(b == *a as _).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(Literal::String(a)), ConValue::String(b)) => {
|
|
||||||
(*a == *b).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(_), _) => Err(Error::NotAssignable()),
|
|
||||||
|
|
||||||
(Pattern::Rest(Some(pat)), value) => match (pat.as_ref(), value) {
|
|
||||||
(Pattern::Literal(Literal::Int(a)), ConValue::Int(b)) => {
|
|
||||||
(b < *a as _).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(Literal::Char(a)), ConValue::Char(b)) => {
|
|
||||||
(b < *a as _).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(Literal::Bool(a)), ConValue::Bool(b)) => {
|
|
||||||
(!b & *a).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(Literal::Float(a)), ConValue::Float(b)) => {
|
|
||||||
(b < *a as _).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
(Pattern::Literal(Literal::String(a)), ConValue::String(b)) => {
|
|
||||||
(&*b < a).then_some(()).ok_or(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
_ => Err(Error::NotAssignable()),
|
|
||||||
},
|
|
||||||
|
|
||||||
(Pattern::Name(name), _) if "_".eq(&**name) => Ok(()),
|
|
||||||
(Pattern::Name(name), value) => {
|
|
||||||
sub.insert(name, value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
(Pattern::Ref(_, pat), ConValue::Ref(r)) => {
|
|
||||||
todo!("Dereference <{r}> in pattern matching {pat}")
|
|
||||||
}
|
|
||||||
|
|
||||||
(Pattern::RangeExc(head, tail), value) => match (head.as_ref(), tail.as_ref(), value) {
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::Int(a)),
|
|
||||||
Pattern::Literal(Literal::Int(c)),
|
|
||||||
ConValue::Int(b),
|
|
||||||
) => (*a as isize <= b as _ && b < *c as isize)
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::Char(a)),
|
|
||||||
Pattern::Literal(Literal::Char(c)),
|
|
||||||
ConValue::Char(b),
|
|
||||||
) => (*a <= b && b < *c)
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::Float(a)),
|
|
||||||
Pattern::Literal(Literal::Float(c)),
|
|
||||||
ConValue::Float(b),
|
|
||||||
) => (f64::from_bits(*a) <= b && b < f64::from_bits(*c))
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::String(a)),
|
|
||||||
Pattern::Literal(Literal::String(c)),
|
|
||||||
ConValue::String(b),
|
|
||||||
) => (a.as_str() <= b.to_ref() && b.to_ref() < c.as_str())
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
_ => Err(Error::NotAssignable()),
|
|
||||||
},
|
|
||||||
|
|
||||||
(Pattern::RangeInc(head, tail), value) => match (head.as_ref(), tail.as_ref(), value) {
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::Int(a)),
|
|
||||||
Pattern::Literal(Literal::Int(c)),
|
|
||||||
ConValue::Int(b),
|
|
||||||
) => (*a as isize <= b && b <= *c as isize)
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::Char(a)),
|
|
||||||
Pattern::Literal(Literal::Char(c)),
|
|
||||||
ConValue::Char(b),
|
|
||||||
) => (*a <= b && b <= *c)
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::Float(a)),
|
|
||||||
Pattern::Literal(Literal::Float(c)),
|
|
||||||
ConValue::Float(b),
|
|
||||||
) => (f64::from_bits(*a) <= b && b <= f64::from_bits(*c))
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
(
|
|
||||||
Pattern::Literal(Literal::String(a)),
|
|
||||||
Pattern::Literal(Literal::String(c)),
|
|
||||||
ConValue::String(b),
|
|
||||||
) => (a.as_str() <= b.to_ref() && b.to_ref() <= c.as_str())
|
|
||||||
.then_some(())
|
|
||||||
.ok_or(Error::NotAssignable()),
|
|
||||||
_ => Err(Error::NotAssignable()),
|
|
||||||
},
|
|
||||||
|
|
||||||
(Pattern::Array(patterns), ConValue::Array(values)) => {
|
|
||||||
match rest_binding(sub, patterns, values.into_vec().into())? {
|
|
||||||
Some((pattern, values)) => {
|
|
||||||
append_sub(sub, pattern, ConValue::Array(Vec::from(values).into()))
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(Pattern::Tuple(patterns), ConValue::Empty) if patterns.is_empty() => Ok(()),
|
|
||||||
(Pattern::Tuple(patterns), ConValue::Tuple(values)) => {
|
|
||||||
match rest_binding(sub, patterns, values.into_vec().into())? {
|
|
||||||
Some((pattern, values)) => {
|
|
||||||
append_sub(sub, pattern, ConValue::Tuple(Vec::from(values).into()))
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(Pattern::TupleStruct(path, patterns), ConValue::TupleStruct(parts)) => {
|
|
||||||
let (name, values) = *parts;
|
|
||||||
if !path.ends_with(name) {
|
|
||||||
Err(Error::TypeError())?
|
|
||||||
}
|
|
||||||
match rest_binding(sub, patterns, values.into_vec().into())? {
|
|
||||||
Some((pattern, values)) => {
|
|
||||||
append_sub(sub, pattern, ConValue::Tuple(Vec::from(values).into()))
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(Pattern::Struct(path, patterns), ConValue::Struct(parts)) => {
|
|
||||||
let (name, mut values) = *parts;
|
|
||||||
if !path.ends_with(&name) {
|
|
||||||
Err(Error::TypeError())?
|
|
||||||
}
|
|
||||||
for (name, pat) in patterns {
|
|
||||||
let value = values.remove(name).ok_or(Error::TypeError())?;
|
|
||||||
match pat {
|
|
||||||
Some(pat) => append_sub(sub, pat, value)?,
|
|
||||||
None => {
|
|
||||||
sub.insert(name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
// eprintln!("Could not match pattern `{pat}` with value `{value}`!");
|
|
||||||
Err(Error::NotAssignable())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a substitution from a pattern and a value
|
|
||||||
pub fn substitution(pat: &Pattern, value: ConValue) -> IResult<HashMap<&Sym, ConValue>> {
|
|
||||||
let mut sub = HashMap::new();
|
|
||||||
append_sub(&mut sub, pat, value)?;
|
|
||||||
Ok(sub)
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
use crate::{Interpret, convalue::ConValue, env::Environment};
|
use crate::{convalue::ConValue, env::Environment, Interpret};
|
||||||
use cl_ast::*;
|
use cl_ast::*;
|
||||||
use cl_lexer::Lexer;
|
use cl_lexer::Lexer;
|
||||||
use cl_parser::Parser;
|
use cl_parser::Parser;
|
||||||
@ -71,7 +71,7 @@ mod macros {
|
|||||||
///
|
///
|
||||||
/// Returns a `Result<`[`Block`]`, ParseError>`
|
/// Returns a `Result<`[`Block`]`, ParseError>`
|
||||||
pub macro block($($t:tt)*) {
|
pub macro block($($t:tt)*) {
|
||||||
Block::parse(&mut Parser::new("test", Lexer::new(stringify!({ $($t)* }))))
|
Block::parse(&mut Parser::new(Lexer::new(stringify!({ $($t)* }))))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates a block of code in the given environment
|
/// Evaluates a block of code in the given environment
|
||||||
@ -530,25 +530,6 @@ mod control_flow {
|
|||||||
env_eq!(env.evaluated, "fail");
|
env_eq!(env.evaluated, "fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn while_evaluates_fail_block_on_false() {
|
|
||||||
let mut env = Default::default();
|
|
||||||
assert_eval!(env,
|
|
||||||
let cond = true;
|
|
||||||
let evaluated = while cond { cond = false } else { true }
|
|
||||||
);
|
|
||||||
env_eq!(env.evaluated, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn while_does_not_evaluate_fail_block_on_break() {
|
|
||||||
let mut env = Default::default();
|
|
||||||
assert_eval!(env,
|
|
||||||
let evaluated = while true { break true } else { false }
|
|
||||||
);
|
|
||||||
env_eq!(env.evaluated, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_evaluates_in_order() {
|
fn match_evaluates_in_order() {
|
||||||
let mut env = Default::default();
|
let mut env = Default::default();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use cl_ast::{Expr, Sym};
|
|
||||||
use cl_lexer::error::{Error as LexError, Reason};
|
use cl_lexer::error::{Error as LexError, Reason};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
pub type PResult<T> = Result<T, Error>;
|
pub type PResult<T> = Result<T, Error>;
|
||||||
@ -8,7 +7,6 @@ pub type PResult<T> = Result<T, Error>;
|
|||||||
/// Contains information about [Parser] errors
|
/// Contains information about [Parser] errors
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
pub in_file: Sym,
|
|
||||||
pub reason: ErrorKind,
|
pub reason: ErrorKind,
|
||||||
pub while_parsing: Parsing,
|
pub while_parsing: Parsing,
|
||||||
pub loc: Loc,
|
pub loc: Loc,
|
||||||
@ -31,7 +29,6 @@ pub enum ErrorKind {
|
|||||||
ExpectedParsing {
|
ExpectedParsing {
|
||||||
want: Parsing,
|
want: Parsing,
|
||||||
},
|
},
|
||||||
InvalidPattern(Box<Expr>),
|
|
||||||
/// Indicates unfinished code
|
/// Indicates unfinished code
|
||||||
Todo(&'static str),
|
Todo(&'static str),
|
||||||
}
|
}
|
||||||
@ -60,7 +57,6 @@ pub enum Parsing {
|
|||||||
|
|
||||||
Item,
|
Item,
|
||||||
ItemKind,
|
ItemKind,
|
||||||
Generics,
|
|
||||||
Alias,
|
Alias,
|
||||||
Const,
|
Const,
|
||||||
Static,
|
Static,
|
||||||
@ -97,7 +93,6 @@ pub enum Parsing {
|
|||||||
|
|
||||||
Expr,
|
Expr,
|
||||||
ExprKind,
|
ExprKind,
|
||||||
Closure,
|
|
||||||
Assign,
|
Assign,
|
||||||
AssignKind,
|
AssignKind,
|
||||||
Binary,
|
Binary,
|
||||||
@ -132,18 +127,13 @@ pub enum Parsing {
|
|||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self { in_file, reason, while_parsing, loc } = self;
|
let Self { reason, while_parsing, loc } = self;
|
||||||
match reason {
|
match reason {
|
||||||
// TODO entries are debug-printed
|
// TODO entries are debug-printed
|
||||||
ErrorKind::Todo(_) => write!(f, "{in_file}:{loc} {reason} {while_parsing:?}"),
|
ErrorKind::Todo(_) => write!(f, "{loc} {reason} {while_parsing:?}"),
|
||||||
// lexical errors print their own higher-resolution loc info
|
// lexical errors print their own higher-resolution loc info
|
||||||
ErrorKind::Lexical(e) => write!(f, "{e} (while parsing {while_parsing})"),
|
ErrorKind::Lexical(e) => write!(f, "{e} (while parsing {while_parsing})"),
|
||||||
_ => {
|
_ => write!(f, "{loc} {reason} while parsing {while_parsing}"),
|
||||||
if !in_file.is_empty() {
|
|
||||||
write!(f, "{in_file}:")?
|
|
||||||
}
|
|
||||||
write!(f, "{loc}: {reason} while parsing {while_parsing}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,7 +148,6 @@ impl Display for ErrorKind {
|
|||||||
ErrorKind::Unexpected(t) => write!(f, "Encountered unexpected token `{t}`"),
|
ErrorKind::Unexpected(t) => write!(f, "Encountered unexpected token `{t}`"),
|
||||||
ErrorKind::ExpectedToken { want: e, got: g } => write!(f, "Expected `{e}`, got `{g}`"),
|
ErrorKind::ExpectedToken { want: e, got: g } => write!(f, "Expected `{e}`, got `{g}`"),
|
||||||
ErrorKind::ExpectedParsing { want } => write!(f, "Expected {want}"),
|
ErrorKind::ExpectedParsing { want } => write!(f, "Expected {want}"),
|
||||||
ErrorKind::InvalidPattern(got) => write!(f, "Got invalid `{got}`"),
|
|
||||||
ErrorKind::Todo(unfinished) => write!(f, "TODO: {unfinished}"),
|
ErrorKind::Todo(unfinished) => write!(f, "TODO: {unfinished}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,7 +167,6 @@ impl Display for Parsing {
|
|||||||
Parsing::MetaKind => "an attribute's arguments",
|
Parsing::MetaKind => "an attribute's arguments",
|
||||||
Parsing::Item => "an item",
|
Parsing::Item => "an item",
|
||||||
Parsing::ItemKind => "an item",
|
Parsing::ItemKind => "an item",
|
||||||
Parsing::Generics => "a list of type arguments",
|
|
||||||
Parsing::Alias => "a type alias",
|
Parsing::Alias => "a type alias",
|
||||||
Parsing::Const => "a const item",
|
Parsing::Const => "a const item",
|
||||||
Parsing::Static => "a static variable",
|
Parsing::Static => "a static variable",
|
||||||
@ -215,7 +203,6 @@ impl Display for Parsing {
|
|||||||
|
|
||||||
Parsing::Expr => "an expression",
|
Parsing::Expr => "an expression",
|
||||||
Parsing::ExprKind => "an expression",
|
Parsing::ExprKind => "an expression",
|
||||||
Parsing::Closure => "an anonymous function",
|
|
||||||
Parsing::Assign => "an assignment",
|
Parsing::Assign => "an assignment",
|
||||||
Parsing::AssignKind => "an assignment operator",
|
Parsing::AssignKind => "an assignment operator",
|
||||||
Parsing::Binary => "a binary expression",
|
Parsing::Binary => "a binary expression",
|
||||||
|
@ -48,71 +48,51 @@ impl ModuleInliner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Records an [I/O error](std::io::Error) for later
|
/// Records an [I/O error](std::io::Error) for later
|
||||||
fn handle_io_error(&mut self, error: std::io::Error) -> Option<File> {
|
fn handle_io_error(&mut self, error: std::io::Error) -> ModuleKind {
|
||||||
self.io_errs.push((self.path.clone(), error));
|
self.io_errs.push((self.path.clone(), error));
|
||||||
None
|
ModuleKind::Outline
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Records a [parse error](crate::error::Error) for later
|
/// Records a [parse error](crate::error::Error) for later
|
||||||
fn handle_parse_error(&mut self, error: crate::error::Error) -> Option<File> {
|
fn handle_parse_error(&mut self, error: crate::error::Error) -> ModuleKind {
|
||||||
self.parse_errs.push((self.path.clone(), error));
|
self.parse_errs.push((self.path.clone(), error));
|
||||||
None
|
ModuleKind::Outline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fold for ModuleInliner {
|
impl Fold for ModuleInliner {
|
||||||
/// Traverses down the module tree, entering ever nested directories
|
/// Traverses down the module tree, entering ever nested directories
|
||||||
fn fold_module(&mut self, m: Module) -> Module {
|
fn fold_module(&mut self, m: Module) -> Module {
|
||||||
let Module { name, file } = m;
|
let Module { name, kind } = m;
|
||||||
self.path.push(&*name); // cd ./name
|
self.path.push(&*name); // cd ./name
|
||||||
|
|
||||||
let file = self.fold_module_kind(file);
|
let kind = self.fold_module_kind(kind);
|
||||||
|
|
||||||
self.path.pop(); // cd ..
|
self.path.pop(); // cd ..
|
||||||
Module { name, file }
|
Module { name, kind }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleInliner {
|
|
||||||
/// Attempts to read and parse a file for every module in the tree
|
/// Attempts to read and parse a file for every module in the tree
|
||||||
fn fold_module_kind(&mut self, m: Option<File>) -> Option<File> {
|
fn fold_module_kind(&mut self, m: ModuleKind) -> ModuleKind {
|
||||||
use std::borrow::Cow;
|
if let ModuleKind::Inline(f) = m {
|
||||||
if let Some(f) = m {
|
return ModuleKind::Inline(self.fold_file(f));
|
||||||
return Some(self.fold_file(f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cd path/mod.cl
|
// cd path/mod.cl
|
||||||
self.path.set_extension("cl");
|
self.path.set_extension("cl");
|
||||||
let mut used_path: Cow<Path> = Cow::Borrowed(&self.path);
|
|
||||||
|
|
||||||
let file = match std::fs::read_to_string(&self.path) {
|
let file = match std::fs::read_to_string(&self.path) {
|
||||||
Err(error) => {
|
|
||||||
let Some(basename) = self.path.file_name() else {
|
|
||||||
return self.handle_io_error(error);
|
|
||||||
};
|
|
||||||
used_path = Cow::Owned(
|
|
||||||
self.path
|
|
||||||
.parent()
|
|
||||||
.and_then(Path::parent)
|
|
||||||
.map(|path| path.join(basename))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
match std::fs::read_to_string(&used_path) {
|
|
||||||
Err(error) => return self.handle_io_error(error),
|
Err(error) => return self.handle_io_error(error),
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(file) => file,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match Parser::new(used_path.display().to_string(), Lexer::new(&file)).parse() {
|
let kind = match Parser::new(Lexer::new(&file)).parse() {
|
||||||
Err(e) => self.handle_parse_error(e),
|
Err(e) => return self.handle_parse_error(e),
|
||||||
Ok(file) => {
|
Ok(file) => ModuleKind::Inline(file),
|
||||||
|
};
|
||||||
|
// cd path/mod
|
||||||
self.path.set_extension("");
|
self.path.set_extension("");
|
||||||
|
|
||||||
// The newly loaded module may need further inlining
|
// The newly loaded module may need further inlining
|
||||||
Some(self.fold_file(file))
|
self.fold_module_kind(kind)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,6 @@ mod prec;
|
|||||||
/// Parses a sequence of [Tokens](Token) into an [AST](cl_ast)
|
/// Parses a sequence of [Tokens](Token) into an [AST](cl_ast)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Parser<'t> {
|
pub struct Parser<'t> {
|
||||||
/// Name of the file being parsed
|
|
||||||
file: Sym,
|
|
||||||
/// Lazy tokenizer
|
/// Lazy tokenizer
|
||||||
lexer: Lexer<'t>,
|
lexer: Lexer<'t>,
|
||||||
/// Look-ahead buffer
|
/// Look-ahead buffer
|
||||||
@ -25,8 +23,8 @@ pub struct Parser<'t> {
|
|||||||
|
|
||||||
/// Basic parser functionality
|
/// Basic parser functionality
|
||||||
impl<'t> Parser<'t> {
|
impl<'t> Parser<'t> {
|
||||||
pub fn new(filename: impl AsRef<str>, lexer: Lexer<'t>) -> Self {
|
pub fn new(lexer: Lexer<'t>) -> Self {
|
||||||
Self { file: filename.as_ref().into(), loc: Loc::from(&lexer), lexer, next: None }
|
Self { loc: Loc::from(&lexer), lexer, next: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the location of the last consumed [Token]
|
/// Gets the location of the last consumed [Token]
|
||||||
@ -42,7 +40,7 @@ impl<'t> Parser<'t> {
|
|||||||
|
|
||||||
/// Constructs an [Error]
|
/// Constructs an [Error]
|
||||||
pub fn error(&self, reason: ErrorKind, while_parsing: Parsing) -> Error {
|
pub fn error(&self, reason: ErrorKind, while_parsing: Parsing) -> Error {
|
||||||
Error { in_file: self.file, reason, while_parsing, loc: self.loc }
|
Error { reason, while_parsing, loc: self.loc }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal impl of peek and consume
|
/// Internal impl of peek and consume
|
||||||
@ -188,7 +186,11 @@ macro literal_like() {
|
|||||||
|
|
||||||
/// Expands to a pattern which matches path-like [TokenKinds](TokenKind)
|
/// Expands to a pattern which matches path-like [TokenKinds](TokenKind)
|
||||||
macro path_like() {
|
macro path_like() {
|
||||||
TokenKind::Super | TokenKind::SelfTy | TokenKind::Identifier | TokenKind::ColonColon
|
TokenKind::Super
|
||||||
|
| TokenKind::SelfKw
|
||||||
|
| TokenKind::SelfTy
|
||||||
|
| TokenKind::Identifier
|
||||||
|
| TokenKind::ColonColon
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Parse<'t>: Sized {
|
pub trait Parse<'t>: Sized {
|
||||||
@ -258,10 +260,9 @@ impl Parse<'_> for File {
|
|||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(e) => Err(e)?,
|
Err(e) => Err(e)?,
|
||||||
} {
|
} {
|
||||||
items.push(Item::parse(p)?);
|
items.push(Item::parse(p)?)
|
||||||
let _ = p.match_type(TokenKind::Semi, Parsing::File);
|
|
||||||
}
|
}
|
||||||
Ok(File { name: p.file.to_ref(), items })
|
Ok(File { items })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,13 +292,17 @@ impl Parse<'_> for MetaKind {
|
|||||||
/// Parses data associated with a [Meta] attribute
|
/// Parses data associated with a [Meta] attribute
|
||||||
fn parse(p: &mut Parser) -> PResult<MetaKind> {
|
fn parse(p: &mut Parser) -> PResult<MetaKind> {
|
||||||
const P: Parsing = Parsing::Meta;
|
const P: Parsing = Parsing::Meta;
|
||||||
let tuple = delim(sep(Parse::parse, TokenKind::Comma, PARENS.1, P), PARENS, P);
|
let lit_tuple = delim(
|
||||||
|
sep(Literal::parse, TokenKind::Comma, PARENS.1, P),
|
||||||
|
PARENS,
|
||||||
|
P,
|
||||||
|
);
|
||||||
Ok(match p.peek_kind(P) {
|
Ok(match p.peek_kind(P) {
|
||||||
Ok(TokenKind::Eq) => {
|
Ok(TokenKind::Eq) => {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
MetaKind::Equals(p.parse()?)
|
MetaKind::Equals(Literal::parse(p)?)
|
||||||
}
|
}
|
||||||
Ok(TokenKind::LParen) => MetaKind::Func(tuple(p)?),
|
Ok(TokenKind::LParen) => MetaKind::Func(lit_tuple(p)?),
|
||||||
_ => MetaKind::Plain,
|
_ => MetaKind::Plain,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -315,7 +320,7 @@ impl Parse<'_> for Item {
|
|||||||
attrs: Attrs::parse(p)?,
|
attrs: Attrs::parse(p)?,
|
||||||
vis: Visibility::parse(p)?,
|
vis: Visibility::parse(p)?,
|
||||||
kind: ItemKind::parse(p)?,
|
kind: ItemKind::parse(p)?,
|
||||||
span: Span(start, p.loc()),
|
extents: Span(start, p.loc()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,35 +331,20 @@ impl Parse<'_> for ItemKind {
|
|||||||
/// See also: [Item::parse]
|
/// See also: [Item::parse]
|
||||||
fn parse(p: &mut Parser) -> PResult<Self> {
|
fn parse(p: &mut Parser) -> PResult<Self> {
|
||||||
Ok(match p.peek_kind(Parsing::Item)? {
|
Ok(match p.peek_kind(Parsing::Item)? {
|
||||||
TokenKind::Type => ItemKind::Alias(p.parse()?),
|
TokenKind::Type => Alias::parse(p)?.into(),
|
||||||
TokenKind::Const => ItemKind::Const(p.parse()?),
|
TokenKind::Const => Const::parse(p)?.into(),
|
||||||
TokenKind::Static => ItemKind::Static(p.parse()?),
|
TokenKind::Static => Static::parse(p)?.into(),
|
||||||
TokenKind::Mod => ItemKind::Module(p.parse()?),
|
TokenKind::Mod => Module::parse(p)?.into(),
|
||||||
TokenKind::Fn => ItemKind::Function(p.parse()?),
|
TokenKind::Fn => Function::parse(p)?.into(),
|
||||||
TokenKind::Struct => ItemKind::Struct(p.parse()?),
|
TokenKind::Struct => Struct::parse(p)?.into(),
|
||||||
TokenKind::Enum => ItemKind::Enum(p.parse()?),
|
TokenKind::Enum => Enum::parse(p)?.into(),
|
||||||
TokenKind::Impl => ItemKind::Impl(p.parse()?),
|
TokenKind::Impl => Impl::parse(p)?.into(),
|
||||||
TokenKind::Use => ItemKind::Use(p.parse()?),
|
TokenKind::Use => Use::parse(p)?.into(),
|
||||||
t => Err(p.error(Unexpected(t), Parsing::Item))?,
|
t => Err(p.error(Unexpected(t), Parsing::Item))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse<'_> for Generics {
|
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
|
||||||
const P: Parsing = Parsing::Generics;
|
|
||||||
let vars = match p.peek_kind(P)? {
|
|
||||||
TokenKind::Lt => delim(
|
|
||||||
sep(Sym::parse, TokenKind::Comma, TokenKind::Gt, P),
|
|
||||||
(TokenKind::Lt, TokenKind::Gt),
|
|
||||||
P,
|
|
||||||
)(p)?,
|
|
||||||
_ => Vec::new(),
|
|
||||||
};
|
|
||||||
Ok(Generics { vars })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse<'_> for Alias {
|
impl Parse<'_> for Alias {
|
||||||
/// Parses a [`type` alias](Alias)
|
/// Parses a [`type` alias](Alias)
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
@ -362,9 +352,9 @@ impl Parse<'_> for Alias {
|
|||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
let out = Ok(Alias {
|
let out = Ok(Alias {
|
||||||
name: Sym::parse(p)?,
|
to: Sym::parse(p)?,
|
||||||
from: if p.match_type(TokenKind::Eq, P).is_ok() {
|
from: if p.match_type(TokenKind::Eq, P).is_ok() {
|
||||||
Some(p.parse()?)
|
Some(Ty::parse(p)?.into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
@ -388,7 +378,7 @@ impl Parse<'_> for Const {
|
|||||||
},
|
},
|
||||||
init: {
|
init: {
|
||||||
p.match_type(TokenKind::Eq, P)?;
|
p.match_type(TokenKind::Eq, P)?;
|
||||||
p.parse()?
|
Expr::parse(p)?.into()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
p.match_type(TokenKind::Semi, P)?;
|
p.match_type(TokenKind::Semi, P)?;
|
||||||
@ -407,11 +397,11 @@ impl Parse<'_> for Static {
|
|||||||
name: Sym::parse(p)?,
|
name: Sym::parse(p)?,
|
||||||
ty: {
|
ty: {
|
||||||
p.match_type(TokenKind::Colon, P)?;
|
p.match_type(TokenKind::Colon, P)?;
|
||||||
p.parse()?
|
Ty::parse(p)?.into()
|
||||||
},
|
},
|
||||||
init: {
|
init: {
|
||||||
p.match_type(TokenKind::Eq, P)?;
|
p.match_type(TokenKind::Eq, P)?;
|
||||||
p.parse()?
|
Expr::parse(p)?.into()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
p.match_type(TokenKind::Semi, P)?;
|
p.match_type(TokenKind::Semi, P)?;
|
||||||
@ -424,22 +414,24 @@ impl Parse<'_> for Module {
|
|||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
Ok(Module {
|
Ok(Module { name: Sym::parse(p)?, kind: ModuleKind::parse(p)? })
|
||||||
name: Sym::parse(p)?,
|
}
|
||||||
file: {
|
}
|
||||||
|
|
||||||
|
impl Parse<'_> for ModuleKind {
|
||||||
|
/// Parses the item list associated with a [Module], if present
|
||||||
|
fn parse(p: &mut Parser) -> PResult<ModuleKind> {
|
||||||
const P: Parsing = Parsing::ModuleKind;
|
const P: Parsing = Parsing::ModuleKind;
|
||||||
let inline = delim(Parse::parse, CURLIES, P);
|
let inline = delim(Parse::parse, CURLIES, P);
|
||||||
|
|
||||||
match p.peek_kind(P)? {
|
match p.peek_kind(P)? {
|
||||||
TokenKind::LCurly => Some(inline(p)?),
|
TokenKind::LCurly => Ok(ModuleKind::Inline(inline(p)?)),
|
||||||
TokenKind::Semi => {
|
TokenKind::Semi => {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
None
|
Ok(ModuleKind::Outline)
|
||||||
}
|
}
|
||||||
got => Err(p.error(ExpectedToken { want: TokenKind::Semi, got }, P))?,
|
got => Err(p.error(ExpectedToken { want: TokenKind::Semi, got }, P)),
|
||||||
}
|
}
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +442,6 @@ impl Parse<'_> for Function {
|
|||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
let name = Sym::parse(p)?;
|
let name = Sym::parse(p)?;
|
||||||
let gens = Generics::parse(p)?;
|
|
||||||
let (bind, types) = delim(FnSig::parse, PARENS, P)(p)?;
|
let (bind, types) = delim(FnSig::parse, PARENS, P)(p)?;
|
||||||
let sign = TyFn {
|
let sign = TyFn {
|
||||||
args: Box::new(match types.len() {
|
args: Box::new(match types.len() {
|
||||||
@ -465,21 +456,21 @@ impl Parse<'_> for Function {
|
|||||||
};
|
};
|
||||||
Ok(Function {
|
Ok(Function {
|
||||||
name,
|
name,
|
||||||
gens,
|
|
||||||
sign,
|
sign,
|
||||||
bind,
|
bind,
|
||||||
body: match p.peek_kind(P)? {
|
body: match p.peek_kind(P)? {
|
||||||
|
TokenKind::LCurly => Some(Block::parse(p)?),
|
||||||
TokenKind::Semi => {
|
TokenKind::Semi => {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => Some(Expr::parse(p)?),
|
t => Err(p.error(Unexpected(t), P))?,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FnSig = (Pattern, Vec<TyKind>);
|
type FnSig = (Vec<Param>, Vec<TyKind>);
|
||||||
|
|
||||||
impl Parse<'_> for FnSig {
|
impl Parse<'_> for FnSig {
|
||||||
/// Parses the [parameters](Param) associated with a Function
|
/// Parses the [parameters](Param) associated with a Function
|
||||||
@ -494,21 +485,20 @@ impl Parse<'_> for FnSig {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((Pattern::Tuple(params), types))
|
Ok((params, types))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TypedParam = (Pattern, TyKind);
|
type TypedParam = (Param, TyKind);
|
||||||
|
|
||||||
impl Parse<'_> for TypedParam {
|
impl Parse<'_> for TypedParam {
|
||||||
/// Parses a single function [parameter](Param)
|
/// Parses a single function [parameter](Param)
|
||||||
fn parse(p: &mut Parser) -> PResult<(Pattern, TyKind)> {
|
fn parse(p: &mut Parser) -> PResult<(Param, TyKind)> {
|
||||||
Ok((
|
Ok((
|
||||||
Pattern::parse(p)?,
|
Param { mutability: Mutability::parse(p)?, name: Sym::parse(p)? },
|
||||||
if p.match_type(TokenKind::Colon, Parsing::Param).is_ok() {
|
{
|
||||||
|
p.match_type(TokenKind::Colon, Parsing::Param)?;
|
||||||
TyKind::parse(p)?
|
TyKind::parse(p)?
|
||||||
} else {
|
|
||||||
TyKind::Infer
|
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -518,7 +508,7 @@ impl Parse<'_> for Struct {
|
|||||||
/// Parses a [`struct` definition](Struct)
|
/// Parses a [`struct` definition](Struct)
|
||||||
fn parse(p: &mut Parser) -> PResult<Struct> {
|
fn parse(p: &mut Parser) -> PResult<Struct> {
|
||||||
p.match_type(TokenKind::Struct, Parsing::Struct)?;
|
p.match_type(TokenKind::Struct, Parsing::Struct)?;
|
||||||
Ok(Struct { name: Sym::parse(p)?, gens: Generics::parse(p)?, kind: StructKind::parse(p)? })
|
Ok(Struct { name: Sym::parse(p)?, kind: StructKind::parse(p)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,19 +516,22 @@ impl Parse<'_> for StructKind {
|
|||||||
/// Parses the various [kinds of Struct](StructKind)
|
/// Parses the various [kinds of Struct](StructKind)
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
const P: Parsing = Parsing::StructKind;
|
const P: Parsing = Parsing::StructKind;
|
||||||
Ok(match p.peek_kind(P) {
|
Ok(match p.peek_kind(P)? {
|
||||||
Ok(TokenKind::LParen) => StructKind::Tuple(delim(
|
TokenKind::LParen => StructKind::Tuple(delim(
|
||||||
sep(Ty::parse, TokenKind::Comma, PARENS.1, P),
|
sep(Ty::parse, TokenKind::Comma, PARENS.1, P),
|
||||||
PARENS,
|
PARENS,
|
||||||
P,
|
P,
|
||||||
)(p)?),
|
)(p)?),
|
||||||
Ok(TokenKind::LCurly) => StructKind::Struct(delim(
|
TokenKind::LCurly => StructKind::Struct(delim(
|
||||||
sep(StructMember::parse, TokenKind::Comma, CURLIES.1, P),
|
sep(StructMember::parse, TokenKind::Comma, CURLIES.1, P),
|
||||||
CURLIES,
|
CURLIES,
|
||||||
P,
|
P,
|
||||||
)(p)?),
|
)(p)?),
|
||||||
Ok(_) | Err(Error { reason: ErrorKind::EndOfInput, .. }) => StructKind::Empty,
|
TokenKind::Semi => {
|
||||||
Err(e) => Err(e)?,
|
p.consume_peeked();
|
||||||
|
StructKind::Empty
|
||||||
|
}
|
||||||
|
got => Err(p.error(ExpectedToken { want: TokenKind::Semi, got }, P))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -562,20 +555,26 @@ impl Parse<'_> for Enum {
|
|||||||
/// Parses an [`enum`](Enum) definition
|
/// Parses an [`enum`](Enum) definition
|
||||||
fn parse(p: &mut Parser) -> PResult<Enum> {
|
fn parse(p: &mut Parser) -> PResult<Enum> {
|
||||||
p.match_type(TokenKind::Enum, Parsing::Enum)?;
|
p.match_type(TokenKind::Enum, Parsing::Enum)?;
|
||||||
Ok(Enum {
|
|
||||||
name: Sym::parse(p)?,
|
Ok(Enum { name: Sym::parse(p)?, kind: EnumKind::parse(p)? })
|
||||||
gens: Generics::parse(p)?,
|
}
|
||||||
variants: {
|
}
|
||||||
|
|
||||||
|
impl Parse<'_> for EnumKind {
|
||||||
|
/// Parses the various [kinds of Enum](EnumKind)
|
||||||
|
fn parse(p: &mut Parser<'_>) -> PResult<EnumKind> {
|
||||||
const P: Parsing = Parsing::EnumKind;
|
const P: Parsing = Parsing::EnumKind;
|
||||||
match p.peek_kind(P)? {
|
Ok(match p.peek_kind(P)? {
|
||||||
TokenKind::LCurly => delim(
|
TokenKind::LCurly => EnumKind::Variants(delim(
|
||||||
sep(Variant::parse, TokenKind::Comma, TokenKind::RCurly, P),
|
sep(Variant::parse, TokenKind::Comma, TokenKind::RCurly, P),
|
||||||
CURLIES,
|
CURLIES,
|
||||||
P,
|
P,
|
||||||
)(p)?,
|
)(p)?),
|
||||||
t => Err(p.error(Unexpected(t), P))?,
|
TokenKind::Semi => {
|
||||||
|
p.consume_peeked();
|
||||||
|
EnumKind::NoVariants
|
||||||
}
|
}
|
||||||
},
|
t => Err(p.error(Unexpected(t), P))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -583,19 +582,39 @@ impl Parse<'_> for Enum {
|
|||||||
impl Parse<'_> for Variant {
|
impl Parse<'_> for Variant {
|
||||||
/// Parses an [`enum`](Enum) [Variant]
|
/// Parses an [`enum`](Enum) [Variant]
|
||||||
fn parse(p: &mut Parser) -> PResult<Variant> {
|
fn parse(p: &mut Parser) -> PResult<Variant> {
|
||||||
let name = Sym::parse(p)?;
|
Ok(Variant { name: Sym::parse(p)?, kind: VariantKind::parse(p)? })
|
||||||
let kind;
|
}
|
||||||
let body;
|
|
||||||
|
|
||||||
if p.match_type(TokenKind::Eq, Parsing::Variant).is_ok() {
|
|
||||||
kind = StructKind::Empty;
|
|
||||||
body = Some(Box::new(Expr::parse(p)?));
|
|
||||||
} else {
|
|
||||||
kind = StructKind::parse(p)?;
|
|
||||||
body = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Variant { name, kind, body })
|
impl Parse<'_> for VariantKind {
|
||||||
|
/// Parses the various [kinds of Enum Variant](VariantKind)
|
||||||
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
|
const P: Parsing = Parsing::VariantKind;
|
||||||
|
Ok(match p.peek_kind(P)? {
|
||||||
|
TokenKind::Eq => {
|
||||||
|
p.match_type(TokenKind::Eq, P)?;
|
||||||
|
let tok = p.match_type(TokenKind::Literal, P)?;
|
||||||
|
|
||||||
|
VariantKind::CLike(match tok.data() {
|
||||||
|
TokenData::Integer(i) => *i,
|
||||||
|
_ => panic!("Expected token data for {tok:?} while parsing {P}"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
TokenKind::LCurly => VariantKind::Struct(delim(
|
||||||
|
sep(StructMember::parse, TokenKind::Comma, TokenKind::RCurly, P),
|
||||||
|
CURLIES,
|
||||||
|
P,
|
||||||
|
)(p)?),
|
||||||
|
TokenKind::LParen => {
|
||||||
|
let tup = Ty::parse(p)?;
|
||||||
|
if !matches!(tup.kind, TyKind::Tuple(_) | TyKind::Empty) {
|
||||||
|
Err(p.error(ErrorKind::ExpectedParsing { want: Parsing::TyTuple }, P))?
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantKind::Tuple(tup)
|
||||||
|
}
|
||||||
|
_ => VariantKind::Plain,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,10 +639,9 @@ impl Parse<'_> for ImplKind {
|
|||||||
Ok(ImplKind::Trait { impl_trait, for_type: Ty::parse(p)?.into() })
|
Ok(ImplKind::Trait { impl_trait, for_type: Ty::parse(p)?.into() })
|
||||||
} else {
|
} else {
|
||||||
Err(Error {
|
Err(Error {
|
||||||
in_file: p.file,
|
|
||||||
reason: ExpectedParsing { want: Parsing::Path },
|
reason: ExpectedParsing { want: Parsing::Path },
|
||||||
while_parsing: P,
|
while_parsing: P,
|
||||||
loc: target.span.head,
|
loc: target.extents.head,
|
||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,7 +673,7 @@ impl Parse<'_> for UseTree {
|
|||||||
CURLIES,
|
CURLIES,
|
||||||
P,
|
P,
|
||||||
)(p)?),
|
)(p)?),
|
||||||
TokenKind::Super | TokenKind::Identifier => {
|
TokenKind::SelfKw | TokenKind::Super | TokenKind::Identifier => {
|
||||||
let name = PathPart::parse(p)?;
|
let name = PathPart::parse(p)?;
|
||||||
if p.match_type(TokenKind::ColonColon, P).is_ok() {
|
if p.match_type(TokenKind::ColonColon, P).is_ok() {
|
||||||
UseTree::Path(name, Box::new(UseTree::parse(p)?))
|
UseTree::Path(name, Box::new(UseTree::parse(p)?))
|
||||||
@ -683,7 +701,7 @@ impl Parse<'_> for Ty {
|
|||||||
/// See also: [TyKind::parse]
|
/// See also: [TyKind::parse]
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
let start = p.loc();
|
let start = p.loc();
|
||||||
Ok(Ty { kind: TyKind::parse(p)?, span: Span(start, p.loc()) })
|
Ok(Ty { kind: TyKind::parse(p)?, extents: Span(start, p.loc()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,14 +747,7 @@ impl Parse<'_> for TyKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TokenKind::Fn => TyFn::parse(p)?.into(),
|
TokenKind::Fn => TyFn::parse(p)?.into(),
|
||||||
path_like!() => {
|
path_like!() => Path::parse(p)?.into(),
|
||||||
let path = Path::parse(p)?;
|
|
||||||
if path.is_sinkhole() {
|
|
||||||
TyKind::Infer
|
|
||||||
} else {
|
|
||||||
TyKind::Path(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t => Err(p.error(Unexpected(t), P))?,
|
t => Err(p.error(Unexpected(t), P))?,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -767,7 +778,7 @@ impl Parse<'_> for TyRef {
|
|||||||
}
|
}
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
}
|
}
|
||||||
Ok(TyRef { count, mutable: p.parse()?, to: p.parse()? })
|
Ok(TyRef { count, mutable: Mutability::parse(p)?, to: Path::parse(p)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -830,6 +841,7 @@ impl Parse<'_> for PathPart {
|
|||||||
const P: Parsing = Parsing::PathPart;
|
const P: Parsing = Parsing::PathPart;
|
||||||
let out = match p.peek_kind(P)? {
|
let out = match p.peek_kind(P)? {
|
||||||
TokenKind::Super => PathPart::SuperKw,
|
TokenKind::Super => PathPart::SuperKw,
|
||||||
|
TokenKind::SelfKw => PathPart::SelfKw,
|
||||||
TokenKind::SelfTy => PathPart::SelfTy,
|
TokenKind::SelfTy => PathPart::SelfTy,
|
||||||
TokenKind::Identifier => PathPart::Ident(Sym::parse(p)?),
|
TokenKind::Identifier => PathPart::Ident(Sym::parse(p)?),
|
||||||
t => return Err(p.error(Unexpected(t), P)),
|
t => return Err(p.error(Unexpected(t), P)),
|
||||||
@ -854,7 +866,7 @@ impl Parse<'_> for Stmt {
|
|||||||
Ok(_) => Semi::Terminated,
|
Ok(_) => Semi::Terminated,
|
||||||
_ => Semi::Unterminated,
|
_ => Semi::Unterminated,
|
||||||
},
|
},
|
||||||
span: Span(start, p.loc()),
|
extents: Span(start, p.loc()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -866,8 +878,8 @@ impl Parse<'_> for StmtKind {
|
|||||||
fn parse(p: &mut Parser) -> PResult<StmtKind> {
|
fn parse(p: &mut Parser) -> PResult<StmtKind> {
|
||||||
Ok(match p.peek_kind(Parsing::StmtKind)? {
|
Ok(match p.peek_kind(Parsing::StmtKind)? {
|
||||||
TokenKind::Semi => StmtKind::Empty,
|
TokenKind::Semi => StmtKind::Empty,
|
||||||
item_like!() => StmtKind::Item(p.parse()?),
|
item_like!() => Item::parse(p)?.into(),
|
||||||
_ => StmtKind::Expr(p.parse()?),
|
_ => Expr::parse(p)?.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -876,40 +888,26 @@ impl Parse<'_> for StmtKind {
|
|||||||
|
|
||||||
impl Parse<'_> for Expr {
|
impl Parse<'_> for Expr {
|
||||||
/// Parses an [Expr]
|
/// Parses an [Expr]
|
||||||
|
///
|
||||||
|
/// See also: [ExprKind::parse]
|
||||||
fn parse(p: &mut Parser) -> PResult<Expr> {
|
fn parse(p: &mut Parser) -> PResult<Expr> {
|
||||||
prec::expr(p, 0)
|
let start = p.loc();
|
||||||
|
Ok(Expr { kind: ExprKind::parse(p)?, extents: Span(start, p.loc()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse<'_> for Closure {
|
impl Parse<'_> for ExprKind {
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
/// Parses an [ExprKind] at the lowest precedence level
|
||||||
let args = sep(
|
// Implementer's note: Do not call this from within [prec::exprkind]
|
||||||
Pattern::parse,
|
fn parse(p: &mut Parser<'_>) -> PResult<ExprKind> {
|
||||||
TokenKind::Comma,
|
prec::exprkind(p, 0)
|
||||||
TokenKind::Bar,
|
|
||||||
Parsing::Closure,
|
|
||||||
);
|
|
||||||
|
|
||||||
let arg = match p.peek_kind(Parsing::Closure)? {
|
|
||||||
TokenKind::BarBar => {
|
|
||||||
p.consume_peeked();
|
|
||||||
Box::new(Pattern::Tuple(vec![]))
|
|
||||||
}
|
|
||||||
_ => Box::new(delim(
|
|
||||||
|p| args(p).map(Pattern::Tuple),
|
|
||||||
(TokenKind::Bar, TokenKind::Bar),
|
|
||||||
Parsing::Closure,
|
|
||||||
)(p)?),
|
|
||||||
};
|
|
||||||
let body = p.parse()?;
|
|
||||||
Ok(Closure { arg, body })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse<'_> for Quote {
|
impl Parse<'_> for Quote {
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
let quote = delim(
|
let quote = delim(
|
||||||
Expr::parse,
|
ExprKind::parse,
|
||||||
(TokenKind::Grave, TokenKind::Grave),
|
(TokenKind::Grave, TokenKind::Grave),
|
||||||
Parsing::ExprKind,
|
Parsing::ExprKind,
|
||||||
)(p)?
|
)(p)?
|
||||||
@ -922,15 +920,15 @@ impl Parse<'_> for Let {
|
|||||||
fn parse(p: &mut Parser) -> PResult<Let> {
|
fn parse(p: &mut Parser) -> PResult<Let> {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
Ok(Let {
|
Ok(Let {
|
||||||
mutable: p.parse()?,
|
mutable: Mutability::parse(p)?,
|
||||||
name: p.parse()?,
|
name: Pattern::parse(p)?,
|
||||||
ty: if p.match_type(TokenKind::Colon, Parsing::Let).is_ok() {
|
ty: if p.match_type(TokenKind::Colon, Parsing::Let).is_ok() {
|
||||||
Some(p.parse()?)
|
Some(Ty::parse(p)?.into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
init: if p.match_type(TokenKind::Eq, Parsing::Let).is_ok() {
|
init: if p.match_type(TokenKind::Eq, Parsing::Let).is_ok() {
|
||||||
Some(condition(p)?.into())
|
Some(Expr::parse(p)?.into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
@ -969,7 +967,7 @@ impl Parse<'_> for Fielder {
|
|||||||
Ok(Fielder {
|
Ok(Fielder {
|
||||||
name: Sym::parse(p)?,
|
name: Sym::parse(p)?,
|
||||||
init: match p.match_type(TokenKind::Colon, P) {
|
init: match p.match_type(TokenKind::Colon, P) {
|
||||||
Ok(_) => Some(p.parse()?),
|
Ok(_) => Some(Box::new(Expr::parse(p)?)),
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -983,20 +981,16 @@ impl Parse<'_> for AddrOf {
|
|||||||
match p.peek_kind(P)? {
|
match p.peek_kind(P)? {
|
||||||
TokenKind::Amp => {
|
TokenKind::Amp => {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
Ok(AddrOf { mutable: p.parse()?, expr: p.parse()? })
|
Ok(AddrOf { mutable: Mutability::parse(p)?, expr: ExprKind::parse(p)?.into() })
|
||||||
}
|
}
|
||||||
TokenKind::AmpAmp => {
|
TokenKind::AmpAmp => {
|
||||||
let start = p.loc();
|
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
Ok(AddrOf {
|
Ok(AddrOf {
|
||||||
mutable: Mutability::Not,
|
mutable: Mutability::Not,
|
||||||
expr: Expr {
|
expr: ExprKind::AddrOf(AddrOf {
|
||||||
kind: ExprKind::AddrOf(AddrOf {
|
|
||||||
mutable: Mutability::parse(p)?,
|
mutable: Mutability::parse(p)?,
|
||||||
expr: p.parse()?,
|
expr: ExprKind::parse(p)?.into(),
|
||||||
}),
|
})
|
||||||
span: Span(start, p.loc()),
|
|
||||||
}
|
|
||||||
.into(),
|
.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1013,18 +1007,13 @@ impl Parse<'_> for Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conditions (which precede curly-braced blocks) get special treatment
|
|
||||||
fn condition(p: &mut Parser) -> PResult<Expr> {
|
|
||||||
prec::expr(p, prec::Precedence::Condition.level())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse<'_> for While {
|
impl Parse<'_> for While {
|
||||||
/// [While] = `while` [Expr] [Block] [Else]?
|
/// [While] = `while` [Expr] [Block] [Else]?
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn parse(p: &mut Parser) -> PResult<While> {
|
fn parse(p: &mut Parser) -> PResult<While> {
|
||||||
p.match_type(TokenKind::While, Parsing::While)?;
|
p.match_type(TokenKind::While, Parsing::While)?;
|
||||||
Ok(While {
|
Ok(While {
|
||||||
cond: condition(p)?.into(),
|
cond: Expr::parse(p)?.into(),
|
||||||
pass: Block::parse(p)?.into(),
|
pass: Block::parse(p)?.into(),
|
||||||
fail: Else::parse(p)?
|
fail: Else::parse(p)?
|
||||||
})
|
})
|
||||||
@ -1037,7 +1026,7 @@ impl Parse<'_> for If {
|
|||||||
fn parse(p: &mut Parser) -> PResult<If> {
|
fn parse(p: &mut Parser) -> PResult<If> {
|
||||||
p.match_type(TokenKind::If, Parsing::If)?;
|
p.match_type(TokenKind::If, Parsing::If)?;
|
||||||
Ok(If {
|
Ok(If {
|
||||||
cond: condition(p)?.into(),
|
cond: Expr::parse(p)?.into(),
|
||||||
pass: Block::parse(p)?.into(),
|
pass: Block::parse(p)?.into(),
|
||||||
fail: Else::parse(p)?,
|
fail: Else::parse(p)?,
|
||||||
})
|
})
|
||||||
@ -1045,13 +1034,16 @@ impl Parse<'_> for If {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Parse<'_> for For {
|
impl Parse<'_> for For {
|
||||||
/// [For]: `for` [Pattern] `in` [Expr] [Block] [Else]?
|
/// [For]: `for` Pattern (TODO) `in` [Expr] [Block] [Else]?
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn parse(p: &mut Parser) -> PResult<For> {
|
fn parse(p: &mut Parser) -> PResult<For> {
|
||||||
|
p.match_type(TokenKind::For, Parsing::For)?;
|
||||||
|
let bind = Sym::parse(p)?;
|
||||||
|
p.match_type(TokenKind::In, Parsing::For)?;
|
||||||
Ok(For {
|
Ok(For {
|
||||||
bind: delim(Parse::parse, (TokenKind::For, TokenKind::In), Parsing::For)(p)?,
|
bind,
|
||||||
cond: condition(p)?.into(),
|
cond: Expr::parse(p)?.into(),
|
||||||
pass: p.parse()?,
|
pass: Block::parse(p)?.into(),
|
||||||
fail: Else::parse(p)?,
|
fail: Else::parse(p)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1063,7 +1055,7 @@ impl Parse<'_> for Else {
|
|||||||
match p.peek_kind(Parsing::Else) {
|
match p.peek_kind(Parsing::Else) {
|
||||||
Ok(TokenKind::Else) => {
|
Ok(TokenKind::Else) => {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
Ok(Else { body: Some(p.parse()?) })
|
Ok(Expr::parse(p)?.into())
|
||||||
}
|
}
|
||||||
Ok(_) | Err(Error { reason: EndOfInput, .. }) => Ok(None.into()),
|
Ok(_) | Err(Error { reason: EndOfInput, .. }) => Ok(None.into()),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
@ -1087,106 +1079,11 @@ impl Parse<'_> for Return {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pathpattern(p: &mut Parser<'_>) -> PResult<Pattern> {
|
|
||||||
const P: Parsing = Parsing::Pattern;
|
|
||||||
let name = Path::parse(p)?;
|
|
||||||
|
|
||||||
let struct_members = |p: &mut Parser| {
|
|
||||||
let name = p.parse()?;
|
|
||||||
let pat = if p.match_type(TokenKind::Colon, P).is_ok() {
|
|
||||||
Some(p.parse()?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok((name, pat))
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(match p.peek_kind(Parsing::Pattern)? {
|
|
||||||
TokenKind::LCurly => Pattern::Struct(
|
|
||||||
name,
|
|
||||||
delim(
|
|
||||||
sep(struct_members, TokenKind::Comma, TokenKind::RCurly, P),
|
|
||||||
CURLIES,
|
|
||||||
P,
|
|
||||||
)(p)?,
|
|
||||||
),
|
|
||||||
TokenKind::LParen => Pattern::TupleStruct(
|
|
||||||
name,
|
|
||||||
delim(
|
|
||||||
sep(Parse::parse, TokenKind::Comma, TokenKind::RParen, P),
|
|
||||||
PARENS,
|
|
||||||
P,
|
|
||||||
)(p)?,
|
|
||||||
),
|
|
||||||
_ => name
|
|
||||||
.as_sym()
|
|
||||||
.map(Pattern::Name)
|
|
||||||
.unwrap_or(Pattern::Path(name)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse<'_> for Pattern {
|
impl Parse<'_> for Pattern {
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
const P: Parsing = Parsing::Pattern;
|
let value = prec::exprkind(p, prec::Precedence::Highest.level())?;
|
||||||
let head = match p.peek_kind(P)? {
|
Pattern::try_from(value)
|
||||||
// Name, Path, Struct, TupleStruct
|
.map_err(|_| p.error(ExpectedParsing { want: Parsing::Pattern }, Parsing::Pattern))
|
||||||
TokenKind::Identifier => pathpattern(p)?,
|
|
||||||
// Literal
|
|
||||||
TokenKind::Literal => Pattern::Literal(p.parse()?),
|
|
||||||
// Rest
|
|
||||||
TokenKind::DotDot => {
|
|
||||||
p.consume_peeked();
|
|
||||||
if matches!(
|
|
||||||
p.peek_kind(P),
|
|
||||||
Ok(TokenKind::Identifier | TokenKind::Literal)
|
|
||||||
) {
|
|
||||||
Pattern::Rest(Some(p.parse()?))
|
|
||||||
} else {
|
|
||||||
Pattern::Rest(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ref
|
|
||||||
TokenKind::Amp => {
|
|
||||||
p.consume_peeked();
|
|
||||||
Pattern::Ref(p.parse()?, p.parse()?)
|
|
||||||
}
|
|
||||||
// Ref(Ref)
|
|
||||||
TokenKind::AmpAmp => {
|
|
||||||
p.consume_peeked();
|
|
||||||
Pattern::Ref(
|
|
||||||
Mutability::Not,
|
|
||||||
Box::new(Pattern::Ref(p.parse()?, p.parse()?)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// Tuple
|
|
||||||
TokenKind::LParen => Pattern::Tuple(delim(
|
|
||||||
sep(Parse::parse, TokenKind::Comma, TokenKind::RParen, P),
|
|
||||||
PARENS,
|
|
||||||
P,
|
|
||||||
)(p)?),
|
|
||||||
// Array
|
|
||||||
TokenKind::LBrack => Pattern::Array(delim(
|
|
||||||
sep(Parse::parse, TokenKind::Comma, TokenKind::RBrack, P),
|
|
||||||
BRACKETS,
|
|
||||||
P,
|
|
||||||
)(p)?),
|
|
||||||
_ => {
|
|
||||||
let bad_expr = p.parse()?;
|
|
||||||
Err(p.error(ErrorKind::InvalidPattern(bad_expr), P))?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match p.peek_kind(P) {
|
|
||||||
Ok(TokenKind::DotDot) => {
|
|
||||||
p.consume_peeked();
|
|
||||||
Ok(Pattern::RangeExc(head.into(), p.parse()?))
|
|
||||||
}
|
|
||||||
Ok(TokenKind::DotDotEq) => {
|
|
||||||
p.consume_peeked();
|
|
||||||
Ok(Pattern::RangeInc(head.into(), p.parse()?))
|
|
||||||
}
|
|
||||||
_ => Ok(head),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1194,14 +1091,13 @@ impl Parse<'_> for Match {
|
|||||||
/// [Match] = `match` [Expr] `{` [MatchArm],* `}`
|
/// [Match] = `match` [Expr] `{` [MatchArm],* `}`
|
||||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||||
p.match_type(TokenKind::Match, Parsing::Match)?;
|
p.match_type(TokenKind::Match, Parsing::Match)?;
|
||||||
Ok(Match {
|
let scrutinee = Expr::parse(p)?.into();
|
||||||
scrutinee: condition(p)?.into(),
|
let arms = delim(
|
||||||
arms: delim(
|
|
||||||
sep(MatchArm::parse, TokenKind::Comma, CURLIES.1, Parsing::Match),
|
sep(MatchArm::parse, TokenKind::Comma, CURLIES.1, Parsing::Match),
|
||||||
CURLIES,
|
CURLIES,
|
||||||
Parsing::Match,
|
Parsing::Match,
|
||||||
)(p)?,
|
)(p)?;
|
||||||
})
|
Ok(Match { scrutinee, arms })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,12 +1115,6 @@ impl Parse<'_> for MatchArm {
|
|||||||
fn ret_body(p: &mut Parser, while_parsing: Parsing) -> PResult<Option<Box<Expr>>> {
|
fn ret_body(p: &mut Parser, while_parsing: Parsing) -> PResult<Option<Box<Expr>>> {
|
||||||
Ok(match p.peek_kind(while_parsing)? {
|
Ok(match p.peek_kind(while_parsing)? {
|
||||||
TokenKind::Semi => None,
|
TokenKind::Semi => None,
|
||||||
_ => Some(p.parse()?),
|
_ => Some(Expr::parse(p)?.into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t, P: Parse<'t>> Parse<'t> for Box<P> {
|
|
||||||
fn parse(p: &mut Parser<'t>) -> PResult<Self> {
|
|
||||||
p.parse().map(Box::new)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,16 +8,14 @@
|
|||||||
use super::{Parse, *};
|
use super::{Parse, *};
|
||||||
|
|
||||||
/// Parses an [ExprKind]
|
/// Parses an [ExprKind]
|
||||||
pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
pub fn exprkind(p: &mut Parser, power: u8) -> PResult<ExprKind> {
|
||||||
let parsing = Parsing::ExprKind;
|
let parsing = Parsing::ExprKind;
|
||||||
let start = p.loc();
|
|
||||||
// Prefix expressions
|
// Prefix expressions
|
||||||
let mut head = Expr {
|
let mut head = match p.peek_kind(Parsing::Unary)? {
|
||||||
kind: match p.peek_kind(Parsing::Unary)? {
|
|
||||||
literal_like!() => Literal::parse(p)?.into(),
|
literal_like!() => Literal::parse(p)?.into(),
|
||||||
path_like!() => exprkind_pathlike(p)?,
|
path_like!() => exprkind_pathlike(p)?,
|
||||||
TokenKind::Amp | TokenKind::AmpAmp => AddrOf::parse(p)?.into(),
|
TokenKind::Amp | TokenKind::AmpAmp => AddrOf::parse(p)?.into(),
|
||||||
TokenKind::Bar | TokenKind::BarBar => Closure::parse(p)?.into(),
|
|
||||||
TokenKind::Grave => Quote::parse(p)?.into(),
|
TokenKind::Grave => Quote::parse(p)?.into(),
|
||||||
TokenKind::LCurly => Block::parse(p)?.into(),
|
TokenKind::LCurly => Block::parse(p)?.into(),
|
||||||
TokenKind::LBrack => exprkind_arraylike(p)?,
|
TokenKind::LBrack => exprkind_arraylike(p)?,
|
||||||
@ -35,23 +33,18 @@ pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
op => {
|
op => {
|
||||||
let (kind, prec) =
|
let (kind, prec) = from_prefix(op).ok_or_else(|| p.error(Unexpected(op), parsing))?;
|
||||||
from_prefix(op).ok_or_else(|| p.error(Unexpected(op), parsing))?;
|
|
||||||
let ((), after) = prec.prefix().expect("should have a precedence");
|
let ((), after) = prec.prefix().expect("should have a precedence");
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
Unary { kind, tail: expr(p, after)?.into() }.into()
|
Unary { kind, tail: exprkind(p, after)?.into() }.into()
|
||||||
}
|
}
|
||||||
},
|
|
||||||
span: Span(start, p.loc()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn from_postfix(op: TokenKind) -> Option<Precedence> {
|
fn from_postfix(op: TokenKind) -> Option<Precedence> {
|
||||||
Some(match op {
|
Some(match op {
|
||||||
TokenKind::LBrack => Precedence::Index,
|
TokenKind::LBrack => Precedence::Index,
|
||||||
TokenKind::LParen => Precedence::Call,
|
TokenKind::LParen => Precedence::Call,
|
||||||
TokenKind::LCurly => Precedence::Structor,
|
|
||||||
TokenKind::Dot => Precedence::Member,
|
TokenKind::Dot => Precedence::Member,
|
||||||
TokenKind::As => Precedence::Cast,
|
|
||||||
_ => None?,
|
_ => None?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -62,48 +55,26 @@ pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
|||||||
if before < power {
|
if before < power {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
head = Expr {
|
|
||||||
kind: match op {
|
|
||||||
TokenKind::LBrack => {
|
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
|
head = match op {
|
||||||
|
TokenKind::LBrack => {
|
||||||
let indices =
|
let indices =
|
||||||
sep(Expr::parse, TokenKind::Comma, TokenKind::RBrack, parsing)(p)?;
|
sep(Expr::parse, TokenKind::Comma, TokenKind::RBrack, parsing)(p)?;
|
||||||
p.match_type(TokenKind::RBrack, parsing)?;
|
p.match_type(TokenKind::RBrack, parsing)?;
|
||||||
ExprKind::Index(Index { head: head.into(), indices })
|
ExprKind::Index(Index { head: head.into(), indices })
|
||||||
}
|
}
|
||||||
TokenKind::LParen => {
|
TokenKind::LParen => {
|
||||||
p.consume_peeked();
|
let exprs = sep(Expr::parse, TokenKind::Comma, TokenKind::RParen, parsing)(p)?;
|
||||||
let exprs =
|
|
||||||
sep(Expr::parse, TokenKind::Comma, TokenKind::RParen, parsing)(p)?;
|
|
||||||
p.match_type(TokenKind::RParen, parsing)?;
|
p.match_type(TokenKind::RParen, parsing)?;
|
||||||
Binary {
|
Binary { kind: BinaryKind::Call, parts: (head, Tuple { exprs }.into()).into() }
|
||||||
kind: BinaryKind::Call,
|
|
||||||
parts: (
|
|
||||||
head,
|
|
||||||
Expr { kind: Tuple { exprs }.into(), span: Span(start, p.loc()) },
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
}
|
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
TokenKind::LCurly => match head.kind {
|
|
||||||
ExprKind::Path(path) => ExprKind::Structor(structor_body(p, path)?),
|
|
||||||
_ => break,
|
|
||||||
},
|
|
||||||
TokenKind::Dot => {
|
TokenKind::Dot => {
|
||||||
p.consume_peeked();
|
|
||||||
let kind = MemberKind::parse(p)?;
|
let kind = MemberKind::parse(p)?;
|
||||||
Member { head: Box::new(head), kind }.into()
|
Member { head: Box::new(head), kind }.into()
|
||||||
}
|
}
|
||||||
TokenKind::As => {
|
|
||||||
p.consume_peeked();
|
|
||||||
let ty = Ty::parse(p)?;
|
|
||||||
Cast { head: head.into(), ty }.into()
|
|
||||||
}
|
|
||||||
_ => Err(p.error(Unexpected(op), parsing))?,
|
_ => Err(p.error(Unexpected(op), parsing))?,
|
||||||
},
|
|
||||||
span: Span(start, p.loc()),
|
|
||||||
};
|
};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -115,11 +86,8 @@ pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
|||||||
}
|
}
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
let tail = expr(p, after)?;
|
let tail = exprkind(p, after)?;
|
||||||
head = Expr {
|
head = Binary { kind, parts: (head, tail).into() }.into();
|
||||||
kind: Binary { kind, parts: (head, tail).into() }.into(),
|
|
||||||
span: Span(start, p.loc()),
|
|
||||||
};
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,11 +98,8 @@ pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
|||||||
}
|
}
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
let tail = expr(p, after)?;
|
let tail = exprkind(p, after)?;
|
||||||
head = Expr {
|
head = Modify { kind, parts: (head, tail).into() }.into();
|
||||||
kind: Modify { kind, parts: (head, tail).into() }.into(),
|
|
||||||
span: Span(start, p.loc()),
|
|
||||||
};
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,12 +112,8 @@ pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
|||||||
}
|
}
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
let tail = expr(p, after)?;
|
let tail = exprkind(p, after)?;
|
||||||
head = Expr {
|
head = Assign { parts: (head, tail).into() }.into();
|
||||||
kind: Assign { parts: (head, tail).into() }.into(),
|
|
||||||
span: Span(start, p.loc()),
|
|
||||||
};
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,8 +125,7 @@ pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
|||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
|
|
||||||
let ty = Ty::parse(p)?;
|
let ty = Ty::parse(p)?;
|
||||||
head = Expr { kind: Cast { head: head.into(), ty }.into(), span: Span(start, p.loc()) };
|
head = Cast { head: head.into(), ty }.into();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,16 +161,10 @@ fn exprkind_array_rep(p: &mut Parser) -> PResult<ExprKind> {
|
|||||||
let first = Expr::parse(p)?;
|
let first = Expr::parse(p)?;
|
||||||
Ok(match p.peek_kind(P)? {
|
Ok(match p.peek_kind(P)? {
|
||||||
TokenKind::Semi => ArrayRep {
|
TokenKind::Semi => ArrayRep {
|
||||||
value: first.into(),
|
value: first.kind.into(),
|
||||||
repeat: {
|
repeat: {
|
||||||
p.consume_peeked();
|
p.consume_peeked();
|
||||||
let value = p.match_type(TokenKind::Literal, Parsing::ArrayRep)?;
|
Box::new(exprkind(p, 0)?)
|
||||||
match value.data() {
|
|
||||||
TokenData::Integer(size) => *size as usize,
|
|
||||||
_ => {
|
|
||||||
Err(p.error(ErrorKind::Unexpected(TokenKind::Literal), Parsing::ArrayRep))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
@ -257,13 +211,17 @@ fn exprkind_group(p: &mut Parser) -> PResult<ExprKind> {
|
|||||||
}
|
}
|
||||||
Ok(Tuple { exprs }.into())
|
Ok(Tuple { exprs }.into())
|
||||||
}
|
}
|
||||||
_ => Ok(Group { expr: first.into() }.into()),
|
_ => Ok(Group { expr: first.kind.into() }.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses an expression beginning with a [Path] (i.e. [Path] or [Structor])
|
/// Parses an expression beginning with a [Path] (i.e. [Path] or [Structor])
|
||||||
fn exprkind_pathlike(p: &mut Parser) -> PResult<ExprKind> {
|
fn exprkind_pathlike(p: &mut Parser) -> PResult<ExprKind> {
|
||||||
Path::parse(p).map(Into::into)
|
let head = Path::parse(p)?;
|
||||||
|
Ok(match p.match_type(TokenKind::Colon, Parsing::Path) {
|
||||||
|
Ok(_) => ExprKind::Structor(structor_body(p, head)?),
|
||||||
|
Err(_) => ExprKind::Path(head),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Structor]Body = `{` ([Fielder] `,`)* [Fielder]? `}`
|
/// [Structor]Body = `{` ([Fielder] `,`)* [Fielder]? `}`
|
||||||
@ -286,8 +244,6 @@ fn structor_body(p: &mut Parser, to: Path) -> PResult<Structor> {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Precedence {
|
pub enum Precedence {
|
||||||
Assign,
|
Assign,
|
||||||
Structor, // A structor is never a valid conditional
|
|
||||||
Condition, // Anything that syntactically needs a block following it
|
|
||||||
Logic,
|
Logic,
|
||||||
Compare,
|
Compare,
|
||||||
Range,
|
Range,
|
||||||
@ -300,7 +256,7 @@ pub enum Precedence {
|
|||||||
Cast,
|
Cast,
|
||||||
Member, // left-associative
|
Member, // left-associative
|
||||||
Call,
|
Call,
|
||||||
Deref,
|
Highest,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Precedence {
|
impl Precedence {
|
||||||
@ -313,7 +269,6 @@ impl Precedence {
|
|||||||
match self {
|
match self {
|
||||||
Self::Assign => Some(((), self.level())),
|
Self::Assign => Some(((), self.level())),
|
||||||
Self::Unary => Some(((), self.level())),
|
Self::Unary => Some(((), self.level())),
|
||||||
Self::Deref => Some(((), self.level())),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,9 +284,7 @@ impl Precedence {
|
|||||||
|
|
||||||
pub fn postfix(self) -> Option<(u8, ())> {
|
pub fn postfix(self) -> Option<(u8, ())> {
|
||||||
match self {
|
match self {
|
||||||
Self::Structor | Self::Index | Self::Call | Self::Member | Self::Cast => {
|
Self::Index | Self::Call | Self::Member => Some((self.level(), ())),
|
||||||
Some((self.level(), ()))
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,8 +317,7 @@ impl From<UnaryKind> for Precedence {
|
|||||||
use UnaryKind as Op;
|
use UnaryKind as Op;
|
||||||
match value {
|
match value {
|
||||||
Op::Loop => Precedence::Assign,
|
Op::Loop => Precedence::Assign,
|
||||||
Op::Deref => Precedence::Deref,
|
Op::Deref | Op::Neg | Op::Not | Op::At | Op::Tilde => Precedence::Unary,
|
||||||
_ => Precedence::Unary,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,8 +338,6 @@ operator! {
|
|||||||
Star => Deref,
|
Star => Deref,
|
||||||
Minus => Neg,
|
Minus => Neg,
|
||||||
Bang => Not,
|
Bang => Not,
|
||||||
DotDot => RangeExc,
|
|
||||||
DotDotEq => RangeInc,
|
|
||||||
At => At,
|
At => At,
|
||||||
Tilde => Tilde,
|
Tilde => Tilde,
|
||||||
};
|
};
|
||||||
|
@ -14,9 +14,6 @@ cl-ast = { path = "../cl-ast" }
|
|||||||
cl-lexer = { path = "../cl-lexer" }
|
cl-lexer = { path = "../cl-lexer" }
|
||||||
cl-token = { path = "../cl-token" }
|
cl-token = { path = "../cl-token" }
|
||||||
cl-parser = { path = "../cl-parser" }
|
cl-parser = { path = "../cl-parser" }
|
||||||
cl-typeck = { path = "../cl-typeck" }
|
|
||||||
cl-interpret = { path = "../cl-interpret" }
|
cl-interpret = { path = "../cl-interpret" }
|
||||||
cl-structures = { path = "../cl-structures" }
|
|
||||||
cl-arena = { version = "0", registry = "soft-fish" }
|
|
||||||
repline = { path = "../../repline" }
|
repline = { path = "../../repline" }
|
||||||
argwerk = "0.20.4"
|
argwerk = "0.20.4"
|
||||||
|
@ -1,954 +0,0 @@
|
|||||||
//! Pretty prints a conlang AST in yaml
|
|
||||||
|
|
||||||
use cl_ast::{File, Stmt};
|
|
||||||
use cl_lexer::Lexer;
|
|
||||||
use cl_parser::Parser;
|
|
||||||
use repline::{Repline, error::Error as RlError};
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
if let Some(path) = std::env::args().nth(1) {
|
|
||||||
let f = std::fs::read_to_string(&path).expect("Path must be valid.");
|
|
||||||
let mut parser = Parser::new(path, Lexer::new(&f));
|
|
||||||
let code: File = match parser.parse() {
|
|
||||||
Ok(f) => f,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{e}");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
CLangifier::new().p(&code);
|
|
||||||
println!();
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let mut rl = Repline::new("\x1b[33m", "cl>", "? >");
|
|
||||||
loop {
|
|
||||||
let mut line = match rl.read() {
|
|
||||||
Err(RlError::CtrlC(_)) => break,
|
|
||||||
Err(RlError::CtrlD(line)) => {
|
|
||||||
rl.deny();
|
|
||||||
line
|
|
||||||
}
|
|
||||||
Ok(line) => line,
|
|
||||||
Err(e) => Err(e)?,
|
|
||||||
};
|
|
||||||
if !line.ends_with(';') {
|
|
||||||
line.push(';');
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut parser = Parser::new("stdin", Lexer::new(&line));
|
|
||||||
let code = match parser.parse::<Stmt>() {
|
|
||||||
Ok(code) => {
|
|
||||||
rl.accept();
|
|
||||||
code
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
print!("\x1b[40G\x1bJ\x1b[91m{e}\x1b[0m");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
print!("\x1b[G\x1b[J");
|
|
||||||
CLangifier::new().p(&code);
|
|
||||||
println!();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use clangifier::CLangifier;
|
|
||||||
pub mod clangifier {
|
|
||||||
use crate::clangify::CLangify;
|
|
||||||
use std::{
|
|
||||||
fmt::Display,
|
|
||||||
io::Write,
|
|
||||||
ops::{Add, Deref, DerefMut},
|
|
||||||
};
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct CLangifier {
|
|
||||||
depth: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CLangifier {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn indent(&mut self) -> Section {
|
|
||||||
Section::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints a [Yamlify] value
|
|
||||||
#[inline]
|
|
||||||
pub fn p<T: CLangify + ?Sized>(&mut self, yaml: &T) -> &mut Self {
|
|
||||||
yaml.print(self);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn increase(&mut self) {
|
|
||||||
self.depth += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decrease(&mut self) {
|
|
||||||
self.depth -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_indentation(&self, writer: &mut impl Write) {
|
|
||||||
for _ in 0..self.depth {
|
|
||||||
let _ = write!(writer, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn endl(&mut self) -> &mut Self {
|
|
||||||
self.p("\n")
|
|
||||||
.print_indentation(&mut std::io::stdout().lock());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints a section header and increases indentation
|
|
||||||
pub fn nest(&mut self, name: impl Display) -> Section {
|
|
||||||
print!("{name}");
|
|
||||||
self.indent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: CLangify + ?Sized> Add<&C> for &mut CLangifier {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: &C) -> Self::Output {
|
|
||||||
self.p(rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tracks the start and end of an indented block (a "section")
|
|
||||||
pub struct Section<'y> {
|
|
||||||
yamler: &'y mut CLangifier,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'y> Section<'y> {
|
|
||||||
pub fn new(yamler: &'y mut CLangifier) -> Self {
|
|
||||||
yamler.increase();
|
|
||||||
Self { yamler }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Section<'_> {
|
|
||||||
type Target = CLangifier;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.yamler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl DerefMut for Section<'_> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.yamler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Section<'_> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let Self { yamler } = self;
|
|
||||||
yamler.decrease();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod clangify {
|
|
||||||
use core::panic;
|
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use super::clangifier::CLangifier;
|
|
||||||
use cl_ast::*;
|
|
||||||
|
|
||||||
pub trait CLangify {
|
|
||||||
fn print(&self, y: &mut CLangifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CLangify for File {
|
|
||||||
fn print(&self, mut y: &mut CLangifier) {
|
|
||||||
let File { name, items } = self;
|
|
||||||
// TODO: turn name into include guard
|
|
||||||
y = (y + "// Generated from " + name).endl();
|
|
||||||
for (idx, item) in items.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.endl().endl();
|
|
||||||
}
|
|
||||||
y.p(item);
|
|
||||||
}
|
|
||||||
y.endl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Visibility {
|
|
||||||
fn print(&self, _y: &mut CLangifier) {}
|
|
||||||
}
|
|
||||||
impl CLangify for Mutability {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
if let Mutability::Not = self {
|
|
||||||
y.p("const ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CLangify for Attrs {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { meta } = self;
|
|
||||||
y.nest("Attrs").p(meta);
|
|
||||||
todo!("Attributes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Meta {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, kind } = self;
|
|
||||||
y.nest("Meta").p(name).p(kind);
|
|
||||||
todo!("Attributes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for MetaKind {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
MetaKind::Plain => y,
|
|
||||||
MetaKind::Equals(value) => y.p(value),
|
|
||||||
MetaKind::Func(args) => y.p(args),
|
|
||||||
};
|
|
||||||
todo!("Attributes");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CLangify for Item {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { span: _, attrs: _, vis, kind } = self;
|
|
||||||
y.p(vis).p(kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for ItemKind {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
ItemKind::Alias(f) => y.p(f),
|
|
||||||
ItemKind::Const(f) => y.p(f),
|
|
||||||
ItemKind::Static(f) => y.p(f),
|
|
||||||
ItemKind::Module(f) => y.p(f),
|
|
||||||
ItemKind::Function(f) => y.p(f),
|
|
||||||
ItemKind::Struct(f) => y.p(f),
|
|
||||||
ItemKind::Enum(f) => y.p(f),
|
|
||||||
ItemKind::Impl(f) => y.p(f),
|
|
||||||
ItemKind::Use(f) => y.p(f),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Generics {
|
|
||||||
fn print(&self, _y: &mut CLangifier) {
|
|
||||||
let Self { vars } = self;
|
|
||||||
if !vars.is_empty() {
|
|
||||||
panic!("C doesn't have generics, dumbass.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Alias {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, from } = self;
|
|
||||||
y.p("typedef ").p(from).p(" ");
|
|
||||||
y.p(name).p("; ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Const {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, ty, init } = self;
|
|
||||||
y.p("const ").p(ty).p(" ");
|
|
||||||
y.p(name).p(" = ").p(init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Static {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { mutable, name, ty, init } = self;
|
|
||||||
y.p(mutable).p(ty).p(" ");
|
|
||||||
y.p(name).p(" = ").p(init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Module {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, file } = self;
|
|
||||||
y.nest("// mod ").p(name).p(" {").endl();
|
|
||||||
y.p(file);
|
|
||||||
y.endl().p("// } mod ").p(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Function {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, gens: _, sign, bind, body } = self;
|
|
||||||
let TyFn { args, rety } = sign;
|
|
||||||
let types = match args.as_ref() {
|
|
||||||
TyKind::Tuple(TyTuple { types }) => types.as_slice(),
|
|
||||||
TyKind::Empty => &[],
|
|
||||||
_ => panic!("Unsupported function args: {args}"),
|
|
||||||
};
|
|
||||||
let bind = match bind {
|
|
||||||
Pattern::Tuple(tup) => tup.as_slice(),
|
|
||||||
_ => panic!("Unsupported function binders: {args}"),
|
|
||||||
};
|
|
||||||
match rety {
|
|
||||||
Some(ty) => y.p(ty),
|
|
||||||
None => y.p("void"),
|
|
||||||
}
|
|
||||||
.p(" ")
|
|
||||||
.p(name)
|
|
||||||
.p(" (");
|
|
||||||
for (idx, (bind, ty)) in bind.iter().zip(types).enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
// y.print("/* TODO: desugar pat match args */");
|
|
||||||
y.p(ty).p(" ").p(bind);
|
|
||||||
}
|
|
||||||
y.p(") ").p(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Struct {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, gens: _, kind } = self;
|
|
||||||
y.p("struct ").p(name).nest(" {").p(kind);
|
|
||||||
y.endl().p("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for StructKind {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
StructKind::Empty => y.endl().p("char _zero_sized_t;"),
|
|
||||||
StructKind::Tuple(k) => {
|
|
||||||
for (idx, ty) in k.iter().enumerate() {
|
|
||||||
y.endl().p(ty).p(" _").p(&idx).p(";");
|
|
||||||
}
|
|
||||||
y
|
|
||||||
}
|
|
||||||
StructKind::Struct(k) => y.p(k),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for StructMember {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { vis, name, ty } = self;
|
|
||||||
y.p(vis).p(ty).p(" ").p(name).p(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Enum {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, gens: _, variants } = self;
|
|
||||||
y.nest("enum ").p(name).p(" {").endl();
|
|
||||||
for (idx, variant) in variants.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(",").endl();
|
|
||||||
}
|
|
||||||
y.p(variant);
|
|
||||||
}
|
|
||||||
y.endl().p("\n}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Variant {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, kind, body } = self;
|
|
||||||
y.p(name).p(kind).p(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Impl {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { target, body } = self;
|
|
||||||
y.nest("/* TODO: impl ").p(target).p(" { */ ");
|
|
||||||
y.p(body);
|
|
||||||
y.p("/* } // impl ").p(target).p(" */ ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for ImplKind {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
ImplKind::Type(t) => y.p(t),
|
|
||||||
ImplKind::Trait { impl_trait, for_type } => {
|
|
||||||
todo!("impl {impl_trait} for {for_type}")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Use {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { absolute: _, tree } = self;
|
|
||||||
y.p(tree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for UseTree {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
UseTree::Tree(trees) => y.p(trees),
|
|
||||||
UseTree::Path(path, tree) => y.p("/* ").p(path).p(" */").p(tree),
|
|
||||||
UseTree::Alias(from, to) => y.p("#import <").p(from).p(">.h// ").p(to).p(" "),
|
|
||||||
UseTree::Name(name) => y.p("#import <").p(name).p(".h> "),
|
|
||||||
UseTree::Glob => y.p("/* TODO: use globbing */"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Block {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { stmts } = self;
|
|
||||||
{
|
|
||||||
let mut y = y.nest("{");
|
|
||||||
y.endl();
|
|
||||||
if let [
|
|
||||||
stmts @ ..,
|
|
||||||
Stmt { span: _, kind: StmtKind::Expr(expr), semi: Semi::Unterminated },
|
|
||||||
] = stmts.as_slice()
|
|
||||||
{
|
|
||||||
y.p(stmts).p("return ").p(expr).p(";");
|
|
||||||
} else {
|
|
||||||
y.p(stmts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y.endl().p("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Stmt {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { span: _, kind, semi: _ } = self;
|
|
||||||
y.p(kind).p(";").endl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Semi {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
y.p(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for StmtKind {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
StmtKind::Empty => y,
|
|
||||||
StmtKind::Item(s) => y.p(s),
|
|
||||||
StmtKind::Expr(s) => y.p(s),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Expr {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { span: _, kind } = self;
|
|
||||||
y.p(kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for ExprKind {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
ExprKind::Closure(k) => todo!("Downgrade {k}"),
|
|
||||||
ExprKind::Quote(k) => k.print(y),
|
|
||||||
ExprKind::Let(k) => k.print(y),
|
|
||||||
ExprKind::Match(k) => k.print(y),
|
|
||||||
ExprKind::Assign(k) => k.print(y),
|
|
||||||
ExprKind::Modify(k) => k.print(y),
|
|
||||||
ExprKind::Binary(k) => k.print(y),
|
|
||||||
ExprKind::Unary(k) => k.print(y),
|
|
||||||
ExprKind::Cast(k) => k.print(y),
|
|
||||||
ExprKind::Member(k) => k.print(y),
|
|
||||||
ExprKind::Index(k) => k.print(y),
|
|
||||||
ExprKind::Structor(k) => k.print(y),
|
|
||||||
ExprKind::Path(k) => k.print(y),
|
|
||||||
ExprKind::Literal(k) => k.print(y),
|
|
||||||
ExprKind::Array(k) => k.print(y),
|
|
||||||
ExprKind::ArrayRep(k) => k.print(y),
|
|
||||||
ExprKind::AddrOf(k) => k.print(y),
|
|
||||||
ExprKind::Block(k) => k.print(y),
|
|
||||||
ExprKind::Empty => {}
|
|
||||||
ExprKind::Group(k) => k.print(y),
|
|
||||||
ExprKind::Tuple(k) => k.print(y),
|
|
||||||
ExprKind::While(k) => k.print(y),
|
|
||||||
ExprKind::If(k) => k.print(y),
|
|
||||||
ExprKind::For(k) => k.print(y),
|
|
||||||
ExprKind::Break(k) => k.print(y),
|
|
||||||
ExprKind::Return(k) => k.print(y),
|
|
||||||
ExprKind::Continue => {
|
|
||||||
y.nest("continue");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Quote {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
y.nest("\"");
|
|
||||||
print!("{self}");
|
|
||||||
y.p("\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Let {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { mutable, name, ty, init } = self;
|
|
||||||
let ty = ty.as_deref().map(|ty| &ty.kind).unwrap_or(&TyKind::Infer);
|
|
||||||
match ty {
|
|
||||||
TyKind::Array(TyArray { ty, count }) => {
|
|
||||||
y.p(ty).p(" ").p(mutable).p(name).p("[").p(count).p("]");
|
|
||||||
}
|
|
||||||
TyKind::Fn(TyFn { args, rety }) => {
|
|
||||||
y.nest("(").p(rety).p(" *").p(mutable).p(name).p(")(");
|
|
||||||
match args.as_ref() {
|
|
||||||
TyKind::Empty => {}
|
|
||||||
TyKind::Tuple(TyTuple { types }) => {
|
|
||||||
for (idx, ty) in types.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
y.p(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
y.p(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y.p(")");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
y.indent().p(ty).p(" ").p(mutable).p(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(init) = init {
|
|
||||||
y.p(" = ").p(init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CLangify for Pattern {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
// TODO: Pattern match desugaring!!!
|
|
||||||
match self {
|
|
||||||
Pattern::Name(name) => y.p(name),
|
|
||||||
Pattern::Path(path) => y.p(path),
|
|
||||||
Pattern::Literal(literal) => y.p(literal),
|
|
||||||
Pattern::Rest(name) => y.p("..").p(name),
|
|
||||||
Pattern::Ref(mutability, pattern) => y.p("&").p(mutability).p(pattern),
|
|
||||||
Pattern::RangeExc(head, tail) => y.p("RangeExc").p(head).p(tail),
|
|
||||||
Pattern::RangeInc(head, tail) => y.p("RangeExc").p(head).p(tail),
|
|
||||||
Pattern::Tuple(patterns) => y.nest("Tuple").p(patterns),
|
|
||||||
Pattern::Array(patterns) => y.nest("Array").p(patterns),
|
|
||||||
Pattern::Struct(path, items) => {
|
|
||||||
{
|
|
||||||
let mut y = y.nest("Struct");
|
|
||||||
y.p(path);
|
|
||||||
for (name, item) in items {
|
|
||||||
y.p(name).p(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y
|
|
||||||
}
|
|
||||||
Pattern::TupleStruct(path, items) => {
|
|
||||||
{
|
|
||||||
let mut y = y.nest("TupleStruct");
|
|
||||||
y.p(path).p(items);
|
|
||||||
}
|
|
||||||
y
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Match {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { scrutinee, arms } = self;
|
|
||||||
y.p("/* match ").p(scrutinee);
|
|
||||||
y.nest(" { ").p(arms);
|
|
||||||
y.p(" } */");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CLangify for MatchArm {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self(pat, expr) = self;
|
|
||||||
y.p(pat).p(" => ").p(expr).p(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Assign {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { parts } = self;
|
|
||||||
y.p(&parts.0).p(" = ").p(&parts.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Modify {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { kind, parts } = self;
|
|
||||||
y.p(&parts.0).p(kind).p(&parts.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for ModifyKind {
|
|
||||||
fn print(&self, _y: &mut CLangifier) {
|
|
||||||
print!(" {self} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Binary {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { kind, parts } = self;
|
|
||||||
match kind {
|
|
||||||
BinaryKind::Call => y.p(&parts.0).p(&parts.1),
|
|
||||||
_ => y.p("(").p(&parts.0).p(kind).p(&parts.1).p(")"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for BinaryKind {
|
|
||||||
fn print(&self, _y: &mut CLangifier) {
|
|
||||||
print!(" {self} ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Unary {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { kind, tail } = self;
|
|
||||||
match kind {
|
|
||||||
UnaryKind::Deref => y.p("*").p(tail),
|
|
||||||
UnaryKind::Neg => y.p("-").p(tail),
|
|
||||||
UnaryKind::Not => y.p("!").p(tail),
|
|
||||||
UnaryKind::RangeInc => todo!("Unary RangeInc in C"),
|
|
||||||
UnaryKind::RangeExc => todo!("Unary RangeExc in C"),
|
|
||||||
UnaryKind::Loop => y.nest("while (1) { ").p(tail).p(" }"),
|
|
||||||
UnaryKind::At => todo!(),
|
|
||||||
UnaryKind::Tilde => todo!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Cast {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { head, ty } = self;
|
|
||||||
y.nest("(").p(ty).p(")");
|
|
||||||
y.p(head);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Member {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { head, kind } = self;
|
|
||||||
match kind {
|
|
||||||
MemberKind::Call(name, Tuple { exprs }) => {
|
|
||||||
y.p(name);
|
|
||||||
y.p("(");
|
|
||||||
for (idx, expr) in iter::once(head.as_ref()).chain(exprs).enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
y.p(expr);
|
|
||||||
}
|
|
||||||
y.p(")")
|
|
||||||
}
|
|
||||||
MemberKind::Struct(name) => y.p(head).p(".").p(name),
|
|
||||||
MemberKind::Tuple(idx) => y.p(head).p("._").p(idx),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Tuple {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { exprs } = self;
|
|
||||||
let mut y = y.nest("( ");
|
|
||||||
for (idx, expr) in exprs.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
y.p(expr);
|
|
||||||
}
|
|
||||||
y.p(" )");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Index {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { head, indices } = self;
|
|
||||||
y.p(head);
|
|
||||||
for index in indices {
|
|
||||||
y.p("[").p(index).p("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Structor {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { to, init } = self;
|
|
||||||
y.nest("(").p(to).p(")");
|
|
||||||
{
|
|
||||||
let mut y = y.nest("{ ");
|
|
||||||
for (idx, field) in init.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
y.p(field);
|
|
||||||
}
|
|
||||||
y.p(init);
|
|
||||||
}
|
|
||||||
y.p("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Fielder {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { name, init } = self;
|
|
||||||
y.p(".").p(name).p(" = ").p(init);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Array {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { values } = self;
|
|
||||||
{
|
|
||||||
let mut y = y.nest("{");
|
|
||||||
y.endl();
|
|
||||||
for (idx, value) in values.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
y.p(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y.endl().p("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for ArrayRep {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { value, repeat } = self;
|
|
||||||
{
|
|
||||||
let mut y = y.nest("{");
|
|
||||||
y.endl();
|
|
||||||
for idx in 0..*repeat {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
y.p(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y.endl().p("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for AddrOf {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { mutable: _, expr } = self;
|
|
||||||
y.p("&").p(expr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Group {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { expr } = self;
|
|
||||||
y.p("(").p(expr).p(")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for While {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
// TODO: to properly propagate intermediate values, a new temp variable needs to be
|
|
||||||
// declared on every line lmao. This will require type info.
|
|
||||||
let Self { cond, pass, fail } = self;
|
|
||||||
let Else { body: fail } = fail;
|
|
||||||
y.nest("while(1) {")
|
|
||||||
.endl()
|
|
||||||
.p("if (")
|
|
||||||
.p(cond)
|
|
||||||
.p(") ")
|
|
||||||
.p(pass);
|
|
||||||
{
|
|
||||||
let mut y = y.nest(" else {");
|
|
||||||
y.endl();
|
|
||||||
if let Some(fail) = fail {
|
|
||||||
y.p(fail).p(";").endl();
|
|
||||||
}
|
|
||||||
y.p("break;");
|
|
||||||
}
|
|
||||||
y.endl().p("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Else {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { body } = self;
|
|
||||||
if let Some(body) = body {
|
|
||||||
y.p(" else ").p(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for If {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { cond, pass, fail } = self;
|
|
||||||
y.p("if (").p(cond).p(")");
|
|
||||||
y.p(pass).p(fail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for For {
|
|
||||||
#[rustfmt::skip]
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { bind, cond, pass, fail: _ } = self;
|
|
||||||
let (mode, (head, tail)) = match &cond.kind {
|
|
||||||
ExprKind::Binary(Binary { kind: BinaryKind::RangeExc, parts }) => (false, &**parts),
|
|
||||||
ExprKind::Binary(Binary { kind: BinaryKind::RangeInc, parts }) => (true, &**parts),
|
|
||||||
_ => todo!("Clangify for loops"),
|
|
||||||
};
|
|
||||||
// for (int bind = head; bind mode? < : <= tail; bind++);
|
|
||||||
y.p("for ( int ").p(bind).p(" = ").p(head).p("; ");
|
|
||||||
y.p(bind).p(if mode {"<="} else {"<"}).p(tail).p("; ");
|
|
||||||
y.p("++").p(bind).p(" ) ").p(pass);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Break {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { body } = self;
|
|
||||||
y.nest("break ").p(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Return {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { body } = self;
|
|
||||||
y.nest("return ").p(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Literal {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
Literal::Float(l) => y.p(l),
|
|
||||||
Literal::Bool(l) => y.p(l),
|
|
||||||
Literal::Int(l) => y.p(l),
|
|
||||||
Literal::Char(l) => y.p("'").p(l).p("'"),
|
|
||||||
Literal::String(l) => y.p(&'"').p(l).p(&'"'),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Sym {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
y.p(self.to_ref());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Ty {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { span: _, kind } = self;
|
|
||||||
y.p(kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for TyKind {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
TyKind::Never => y.p("Never"),
|
|
||||||
TyKind::Empty => y.p("Empty"),
|
|
||||||
TyKind::Infer => y.p("Any"),
|
|
||||||
TyKind::Path(t) => y.p(t),
|
|
||||||
TyKind::Tuple(t) => y.p(t),
|
|
||||||
TyKind::Ref(t) => y.p(t),
|
|
||||||
TyKind::Fn(t) => y.p(t),
|
|
||||||
TyKind::Slice(t) => y.p(t),
|
|
||||||
TyKind::Array(t) => y.p(t),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for Path {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { absolute: _, parts } = self;
|
|
||||||
for (idx, part) in parts.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p("_");
|
|
||||||
}
|
|
||||||
y.p(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for PathPart {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
match self {
|
|
||||||
PathPart::SuperKw => y.p("super"),
|
|
||||||
PathPart::SelfTy => y.p("Self"),
|
|
||||||
PathPart::Ident(i) => y.p(i),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for TyArray {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { ty, count } = self;
|
|
||||||
y.p(ty).p("[").p(count).p("]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for TySlice {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { ty } = self;
|
|
||||||
y.p(ty).p("* ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for TyTuple {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { types } = self;
|
|
||||||
{
|
|
||||||
let mut y = y.nest("struct {");
|
|
||||||
y.endl();
|
|
||||||
for (idx, ty) in types.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(",").endl();
|
|
||||||
}
|
|
||||||
y.p(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
y.endl().p("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for TyRef {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { count, mutable, to } = self;
|
|
||||||
y.p(mutable).p(to);
|
|
||||||
for _ in 0..*count {
|
|
||||||
y.p("*");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for TyFn {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
let Self { args, rety } = self;
|
|
||||||
// TODO: function pointer syntax
|
|
||||||
y.nest("(").p(rety).p(" *)(");
|
|
||||||
match args.as_ref() {
|
|
||||||
TyKind::Empty => y,
|
|
||||||
TyKind::Tuple(TyTuple { types }) => {
|
|
||||||
for (idx, ty) in types.iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
y.p(", ");
|
|
||||||
}
|
|
||||||
y.p(ty);
|
|
||||||
}
|
|
||||||
y
|
|
||||||
}
|
|
||||||
_ => y.p(args),
|
|
||||||
}
|
|
||||||
.p(")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: CLangify> CLangify for Option<T> {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
if let Some(v) = self {
|
|
||||||
y.p(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: CLangify> CLangify for Box<T> {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
y.p(&**self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: CLangify> CLangify for Vec<T> {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
for thing in self {
|
|
||||||
y.p(thing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: CLangify> CLangify for [T] {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
for thing in self {
|
|
||||||
y.p(thing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CLangify for () {
|
|
||||||
fn print(&self, _y: &mut CLangifier) {
|
|
||||||
// TODO: C has no language support for zst
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: CLangify> CLangify for &T {
|
|
||||||
fn print(&self, y: &mut CLangifier) {
|
|
||||||
(*self).print(y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CLangify for std::fmt::Arguments<'_> {
|
|
||||||
fn print(&self, _y: &mut CLangifier) {
|
|
||||||
print!("{self}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
macro_rules! scalar {
|
|
||||||
($($t:ty),*$(,)?) => {
|
|
||||||
$(impl CLangify for $t {
|
|
||||||
fn print(&self, _y: &mut CLangifier) {
|
|
||||||
print!("{self}");
|
|
||||||
}
|
|
||||||
})*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
scalar! {
|
|
||||||
bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, str, &str, String
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,7 @@
|
|||||||
use cl_ast::Stmt;
|
use cl_ast::Stmt;
|
||||||
use cl_lexer::Lexer;
|
use cl_lexer::Lexer;
|
||||||
use cl_parser::Parser;
|
use cl_parser::Parser;
|
||||||
use repline::{Repline, error::Error as RlError};
|
use repline::{error::Error as RlError, Repline};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
@ -19,7 +19,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
Err(e) => Err(e)?,
|
Err(e) => Err(e)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut parser = Parser::new("", Lexer::new(&line));
|
let mut parser = Parser::new(Lexer::new(&line));
|
||||||
let code = match parser.parse::<Stmt>() {
|
let code = match parser.parse::<Stmt>() {
|
||||||
Ok(code) => {
|
Ok(code) => {
|
||||||
rl.accept();
|
rl.accept();
|
||||||
@ -41,6 +41,7 @@ pub use yamler::Yamler;
|
|||||||
pub mod yamler {
|
pub mod yamler {
|
||||||
use crate::yamlify::Yamlify;
|
use crate::yamlify::Yamlify;
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
io::Write,
|
io::Write,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
@ -80,25 +81,22 @@ pub mod yamler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a section header and increases indentation
|
/// Prints a section header and increases indentation
|
||||||
pub fn key(&mut self, name: impl Yamlify) -> Section {
|
pub fn key(&mut self, name: impl Display) -> Section {
|
||||||
println!();
|
println!();
|
||||||
self.print_indentation(&mut std::io::stdout().lock());
|
self.print_indentation(&mut std::io::stdout().lock());
|
||||||
print!("- ");
|
print!("- {name}:");
|
||||||
name.yaml(self);
|
|
||||||
print!(":");
|
|
||||||
self.indent()
|
self.indent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a yaml key value pair: `- name: "value"`
|
/// Prints a yaml key value pair: `- name: "value"`
|
||||||
pub fn pair<D: Yamlify, T: Yamlify>(&mut self, name: D, value: T) -> &mut Self {
|
pub fn pair<D: Display, T: Yamlify>(&mut self, name: D, value: T) -> &mut Self {
|
||||||
self.key(name).value(value);
|
self.key(name).yaml(&value);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a yaml scalar value: `"name"``
|
/// Prints a yaml scalar value: `"name"``
|
||||||
pub fn value<D: Yamlify>(&mut self, value: D) -> &mut Self {
|
pub fn value<D: Display>(&mut self, value: D) -> &mut Self {
|
||||||
print!(" ");
|
print!(" {value}");
|
||||||
value.yaml(self);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +150,8 @@ pub mod yamlify {
|
|||||||
|
|
||||||
impl Yamlify for File {
|
impl Yamlify for File {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let File { name, items } = self;
|
let File { items } = self;
|
||||||
y.key("File").pair("name", name).yaml(items);
|
y.key("File").yaml(items);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Visibility {
|
impl Yamlify for Visibility {
|
||||||
@ -195,7 +193,7 @@ pub mod yamlify {
|
|||||||
|
|
||||||
impl Yamlify for Item {
|
impl Yamlify for Item {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { span: _, attrs, vis, kind } = self;
|
let Self { extents: _, attrs, vis, kind } = self;
|
||||||
y.key("Item").yaml(attrs).yaml(vis).yaml(kind);
|
y.key("Item").yaml(attrs).yaml(vis).yaml(kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,16 +212,10 @@ pub mod yamlify {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Generics {
|
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
|
||||||
let Self { vars } = self;
|
|
||||||
y.key("Generics").value(vars);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Yamlify for Alias {
|
impl Yamlify for Alias {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { name, from } = self;
|
let Self { to, from } = self;
|
||||||
y.key("Alias").pair("to", name).pair("from", from);
|
y.key("Alias").pair("to", to).pair("from", from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Const {
|
impl Yamlify for Const {
|
||||||
@ -243,16 +235,23 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
impl Yamlify for Module {
|
impl Yamlify for Module {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { name, file } = self;
|
let Self { name, kind } = self;
|
||||||
y.key("Module").pair("name", name).yaml(file);
|
y.key("Module").pair("name", name).yaml(kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Yamlify for ModuleKind {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
match self {
|
||||||
|
ModuleKind::Inline(f) => y.yaml(f),
|
||||||
|
ModuleKind::Outline => y,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Function {
|
impl Yamlify for Function {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { name, gens, sign, bind, body } = self;
|
let Self { name, sign, bind, body } = self;
|
||||||
y.key("Function")
|
y.key("Function")
|
||||||
.pair("name", name)
|
.pair("name", name)
|
||||||
.pair("gens", gens)
|
|
||||||
.pair("sign", sign)
|
.pair("sign", sign)
|
||||||
.pair("bind", bind)
|
.pair("bind", bind)
|
||||||
.pair("body", body);
|
.pair("body", body);
|
||||||
@ -260,11 +259,8 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
impl Yamlify for Struct {
|
impl Yamlify for Struct {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { name, gens, kind } = self;
|
let Self { name, kind } = self;
|
||||||
y.key("Struct")
|
y.key("Struct").pair("name", name).yaml(kind);
|
||||||
.pair("gens", gens)
|
|
||||||
.pair("name", name)
|
|
||||||
.yaml(kind);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for StructKind {
|
impl Yamlify for StructKind {
|
||||||
@ -284,20 +280,32 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
impl Yamlify for Enum {
|
impl Yamlify for Enum {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { name, gens, variants: kind } = self;
|
let Self { name, kind } = self;
|
||||||
y.key("Enum")
|
y.key("Enum").pair("name", name).yaml(kind);
|
||||||
.pair("gens", gens)
|
}
|
||||||
.pair("name", name)
|
}
|
||||||
.yaml(kind);
|
impl Yamlify for EnumKind {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
match self {
|
||||||
|
EnumKind::NoVariants => y,
|
||||||
|
EnumKind::Variants(v) => y.yaml(v),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Variant {
|
impl Yamlify for Variant {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { name, kind, body } = self;
|
let Self { name, kind } = self;
|
||||||
y.key("Variant")
|
y.key("Variant").pair("name", name).yaml(kind);
|
||||||
.pair("name", name)
|
}
|
||||||
.pair("kind", kind)
|
}
|
||||||
.pair("body", body);
|
impl Yamlify for VariantKind {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
match self {
|
||||||
|
VariantKind::Plain => y,
|
||||||
|
VariantKind::CLike(v) => y.yaml(v),
|
||||||
|
VariantKind::Tuple(v) => y.yaml(v),
|
||||||
|
VariantKind::Struct(v) => y.yaml(v),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Impl {
|
impl Yamlify for Impl {
|
||||||
@ -341,8 +349,8 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
impl Yamlify for Stmt {
|
impl Yamlify for Stmt {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { span: _, kind, semi } = self;
|
let Self { extents: _, kind, semi } = self;
|
||||||
y.key("Stmt").value(kind).yaml(semi);
|
y.key("Stmt").yaml(kind).yaml(semi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Semi {
|
impl Yamlify for Semi {
|
||||||
@ -363,14 +371,13 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
impl Yamlify for Expr {
|
impl Yamlify for Expr {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { span: _, kind } = self;
|
let Self { extents: _, kind } = self;
|
||||||
y.yaml(kind);
|
y.yaml(kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for ExprKind {
|
impl Yamlify for ExprKind {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
match self {
|
match self {
|
||||||
ExprKind::Closure(k) => k.yaml(y),
|
|
||||||
ExprKind::Quote(k) => k.yaml(y),
|
ExprKind::Quote(k) => k.yaml(y),
|
||||||
ExprKind::Let(k) => k.yaml(y),
|
ExprKind::Let(k) => k.yaml(y),
|
||||||
ExprKind::Match(k) => k.yaml(y),
|
ExprKind::Match(k) => k.yaml(y),
|
||||||
@ -402,12 +409,6 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Closure {
|
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
|
||||||
let Self { arg, body } = self;
|
|
||||||
y.key("Closure").pair("arg", arg).pair("body", body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Yamlify for Quote {
|
impl Yamlify for Quote {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
y.key("Quote").value(self);
|
y.key("Quote").value(self);
|
||||||
@ -427,35 +428,23 @@ pub mod yamlify {
|
|||||||
impl Yamlify for Pattern {
|
impl Yamlify for Pattern {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Name(name) => y.value(name),
|
|
||||||
Pattern::Path(path) => y.value(path),
|
Pattern::Path(path) => y.value(path),
|
||||||
Pattern::Literal(literal) => y.value(literal),
|
Pattern::Literal(literal) => y.value(literal),
|
||||||
Pattern::Rest(name) => y.pair("Rest", name),
|
Pattern::Ref(mutability, pattern) => {
|
||||||
Pattern::Ref(mutability, pattern) => y.yaml(mutability).pair("Pat", pattern),
|
y.pair("mutability", mutability).pair("subpattern", pattern)
|
||||||
Pattern::RangeInc(head, tail) => {
|
|
||||||
y.key("RangeInc").pair("head", head).pair("tail", tail);
|
|
||||||
y
|
|
||||||
}
|
}
|
||||||
Pattern::RangeExc(head, tail) => {
|
Pattern::Tuple(patterns) => y.key("Tuple").yaml(patterns),
|
||||||
y.key("RangeExc").pair("head", head).pair("tail", tail);
|
Pattern::Array(patterns) => y.key("Array").yaml(patterns),
|
||||||
y
|
|
||||||
}
|
|
||||||
Pattern::Tuple(patterns) => y.key("Tuple").list(patterns),
|
|
||||||
Pattern::Array(patterns) => y.key("Array").list(patterns),
|
|
||||||
Pattern::Struct(path, items) => {
|
Pattern::Struct(path, items) => {
|
||||||
{
|
{
|
||||||
let mut y = y.key("Struct");
|
let mut y = y.key("Struct");
|
||||||
y.yaml(path);
|
y.pair("name", path);
|
||||||
for (name, item) in items {
|
for (name, item) in items {
|
||||||
y.pair(name, item);
|
y.pair(name, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
y
|
y
|
||||||
}
|
}
|
||||||
Pattern::TupleStruct(path, items) => {
|
|
||||||
y.key("TupleStruct").yaml(path).list(items);
|
|
||||||
y
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -491,6 +480,11 @@ pub mod yamlify {
|
|||||||
.pair("tail", &parts.1);
|
.pair("tail", &parts.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Yamlify for ModifyKind {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
y.value(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Yamlify for Binary {
|
impl Yamlify for Binary {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { kind, parts } = self;
|
let Self { kind, parts } = self;
|
||||||
@ -500,12 +494,22 @@ pub mod yamlify {
|
|||||||
.pair("tail", &parts.1);
|
.pair("tail", &parts.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Yamlify for BinaryKind {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
y.value(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Yamlify for Unary {
|
impl Yamlify for Unary {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { kind, tail } = self;
|
let Self { kind, tail } = self;
|
||||||
y.key("Unary").pair("kind", kind).pair("tail", tail);
|
y.key("Unary").pair("kind", kind).pair("tail", tail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Yamlify for UnaryKind {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
y.value(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Yamlify for Cast {
|
impl Yamlify for Cast {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { head, ty } = self;
|
let Self { head, ty } = self;
|
||||||
@ -621,19 +625,24 @@ pub mod yamlify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Literal {
|
impl Yamlify for Literal {
|
||||||
fn yaml(&self, _y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
match self {
|
y.value(format_args!("\"{self}\""));
|
||||||
Literal::Bool(v) => print!("{v}"),
|
|
||||||
Literal::Char(v) => print!("'{}'", v.escape_debug()),
|
|
||||||
Literal::Int(v) => print!("{v}"),
|
|
||||||
Literal::Float(v) => print!("{v}"),
|
|
||||||
Literal::String(v) => print!("{}", v.escape_debug()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Yamlify for Sym {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
y.value(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Yamlify for Param {
|
||||||
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
|
let Self { mutability, name } = self;
|
||||||
|
y.key("Param").yaml(mutability).pair("name", name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for Ty {
|
impl Yamlify for Ty {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { span: _, kind } = self;
|
let Self { extents: _, kind } = self;
|
||||||
y.key("Ty").yaml(kind);
|
y.key("Ty").yaml(kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -642,13 +651,12 @@ pub mod yamlify {
|
|||||||
match self {
|
match self {
|
||||||
TyKind::Never => y.value("Never"),
|
TyKind::Never => y.value("Never"),
|
||||||
TyKind::Empty => y.value("Empty"),
|
TyKind::Empty => y.value("Empty"),
|
||||||
TyKind::Infer => y.value("_"),
|
|
||||||
TyKind::Path(t) => y.yaml(t),
|
TyKind::Path(t) => y.yaml(t),
|
||||||
TyKind::Tuple(t) => y.yaml(t),
|
TyKind::Tuple(t) => y.yaml(t),
|
||||||
TyKind::Ref(t) => y.yaml(t),
|
TyKind::Ref(t) => y.yaml(t),
|
||||||
TyKind::Fn(t) => y.yaml(t),
|
TyKind::Fn(t) => y.yaml(t),
|
||||||
TyKind::Slice(t) => y.yaml(t),
|
TyKind::Slice(_) => todo!(),
|
||||||
TyKind::Array(t) => y.yaml(t),
|
TyKind::Array(_) => todo!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -668,6 +676,7 @@ pub mod yamlify {
|
|||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
match self {
|
match self {
|
||||||
PathPart::SuperKw => y.value("super"),
|
PathPart::SuperKw => y.value("super"),
|
||||||
|
PathPart::SelfKw => y.value("self"),
|
||||||
PathPart::SelfTy => y.value("Self"),
|
PathPart::SelfTy => y.value("Self"),
|
||||||
PathPart::Ident(i) => y.yaml(i),
|
PathPart::Ident(i) => y.yaml(i),
|
||||||
};
|
};
|
||||||
@ -744,15 +753,14 @@ pub mod yamlify {
|
|||||||
macro_rules! scalar {
|
macro_rules! scalar {
|
||||||
($($t:ty),*$(,)?) => {
|
($($t:ty),*$(,)?) => {
|
||||||
$(impl Yamlify for $t {
|
$(impl Yamlify for $t {
|
||||||
fn yaml(&self, _y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
print!("{self}");
|
y.value(self);
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
scalar! {
|
scalar! {
|
||||||
bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, &str, String,
|
bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, &str, String
|
||||||
BinaryKind, UnaryKind, ModifyKind, Sym,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use cl_ast::File;
|
|||||||
use cl_interpret::{builtin::builtins, convalue::ConValue, env::Environment, interpret::Interpret};
|
use cl_interpret::{builtin::builtins, convalue::ConValue, env::Environment, interpret::Interpret};
|
||||||
use cl_lexer::Lexer;
|
use cl_lexer::Lexer;
|
||||||
use cl_parser::Parser;
|
use cl_parser::Parser;
|
||||||
use std::{borrow::Cow, error::Error, path::Path};
|
use std::{error::Error, path::Path};
|
||||||
|
|
||||||
/// Run the command line interface
|
/// Run the command line interface
|
||||||
pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
|
pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
|
||||||
@ -36,8 +36,6 @@ pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
|
|||||||
fn get_line() {
|
fn get_line() {
|
||||||
match repline::Repline::new("", "", "").read() {
|
match repline::Repline::new("", "", "").read() {
|
||||||
Ok(line) => Ok(ConValue::String(line.into())),
|
Ok(line) => Ok(ConValue::String(line.into())),
|
||||||
Err(repline::Error::CtrlD(line)) => Ok(ConValue::String(line.into())),
|
|
||||||
Err(repline::Error::CtrlC(_)) => Err(cl_interpret::error::Error::Break(ConValue::Empty)),
|
|
||||||
Err(e) => Ok(ConValue::String(e.to_string().into())),
|
Err(e) => Ok(ConValue::String(e.to_string().into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,9 +47,7 @@ pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
if repl {
|
if repl {
|
||||||
if let Some(file) = file {
|
if let Some(file) = file {
|
||||||
if let Err(e) = load_file(&mut env, file) {
|
load_file(&mut env, file)?;
|
||||||
eprintln!("{e}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut ctx = Context::with_env(env);
|
let mut ctx = Context::with_env(env);
|
||||||
match mode {
|
match mode {
|
||||||
@ -61,36 +57,25 @@ pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
|
|||||||
Mode::Run => menu::run(&mut ctx)?,
|
Mode::Run => menu::run(&mut ctx)?,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let path = format_path_for_display(file.as_deref());
|
|
||||||
let code = match &file {
|
let code = match &file {
|
||||||
Some(file) => std::fs::read_to_string(file)?,
|
Some(file) => std::fs::read_to_string(file)?,
|
||||||
None => std::io::read_to_string(std::io::stdin())?,
|
None => std::io::read_to_string(std::io::stdin())?,
|
||||||
};
|
};
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
Mode::Lex => lex_code(&path, &code),
|
Mode::Lex => lex_code(&code, file),
|
||||||
Mode::Fmt => fmt_code(&path, &code),
|
Mode::Fmt => fmt_code(&code),
|
||||||
Mode::Run | Mode::Menu => run_code(&path, &code, &mut env),
|
Mode::Run | Mode::Menu => run_code(&code, &mut env),
|
||||||
}?;
|
}?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_path_for_display(path: Option<&Path>) -> Cow<str> {
|
|
||||||
match path {
|
|
||||||
Some(file) => file
|
|
||||||
.to_str()
|
|
||||||
.map(Cow::Borrowed)
|
|
||||||
.unwrap_or_else(|| Cow::Owned(file.display().to_string())),
|
|
||||||
None => Cow::Borrowed(""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_file(env: &mut Environment, path: impl AsRef<Path>) -> Result<ConValue, Box<dyn Error>> {
|
fn load_file(env: &mut Environment, path: impl AsRef<Path>) -> Result<ConValue, Box<dyn Error>> {
|
||||||
let path = path.as_ref();
|
let inliner =
|
||||||
let inliner = cl_parser::inliner::ModuleInliner::new(path.with_extension(""));
|
cl_parser::inliner::ModuleInliner::new(path.as_ref().parent().unwrap_or(Path::new("")));
|
||||||
let file = std::fs::read_to_string(path)?;
|
let file = std::fs::read_to_string(path)?;
|
||||||
let code = Parser::new(path.display().to_string(), Lexer::new(&file)).parse()?;
|
let code = Parser::new(Lexer::new(&file)).parse()?;
|
||||||
let code = match inliner.inline(code) {
|
let code = match inliner.inline(code) {
|
||||||
Ok(a) => a,
|
Ok(a) => a,
|
||||||
Err((code, io_errs, parse_errs)) => {
|
Err((code, io_errs, parse_errs)) => {
|
||||||
@ -103,22 +88,13 @@ fn load_file(env: &mut Environment, path: impl AsRef<Path>) -> Result<ConValue,
|
|||||||
code
|
code
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
use cl_ast::WeightOf;
|
Ok(env.eval(&code)?)
|
||||||
eprintln!("File {} weighs {} units", code.name, code.weight_of());
|
|
||||||
|
|
||||||
match env.eval(&code) {
|
|
||||||
Ok(v) => Ok(v),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{e}");
|
|
||||||
Ok(ConValue::Empty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lex_code(path: &str, code: &str) -> Result<(), Box<dyn Error>> {
|
fn lex_code(code: &str, path: Option<impl AsRef<Path>>) -> Result<(), Box<dyn Error>> {
|
||||||
for token in Lexer::new(code) {
|
for token in Lexer::new(code) {
|
||||||
if !path.is_empty() {
|
if let Some(path) = &path {
|
||||||
print!("{}:", path);
|
print!("{}:", path.as_ref().display());
|
||||||
}
|
}
|
||||||
match token {
|
match token {
|
||||||
Ok(token) => print_token(&token),
|
Ok(token) => print_token(&token),
|
||||||
@ -128,14 +104,14 @@ fn lex_code(path: &str, code: &str) -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_code(path: &str, code: &str) -> Result<(), Box<dyn Error>> {
|
fn fmt_code(code: &str) -> Result<(), Box<dyn Error>> {
|
||||||
let code = Parser::new(path, Lexer::new(code)).parse::<File>()?;
|
let code = Parser::new(Lexer::new(code)).parse::<File>()?;
|
||||||
println!("{code}");
|
println!("{code}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_code(path: &str, code: &str, env: &mut Environment) -> Result<(), Box<dyn Error>> {
|
fn run_code(code: &str, env: &mut Environment) -> Result<(), Box<dyn Error>> {
|
||||||
let code = Parser::new(path, Lexer::new(code)).parse::<File>()?;
|
let code = Parser::new(Lexer::new(code)).parse::<File>()?;
|
||||||
match code.interpret(env)? {
|
match code.interpret(env)? {
|
||||||
ConValue::Empty => {}
|
ConValue::Empty => {}
|
||||||
ret => println!("{ret}"),
|
ret => println!("{ret}"),
|
||||||
|
@ -47,7 +47,7 @@ pub fn run(ctx: &mut ctx::Context) -> ReplResult<()> {
|
|||||||
if line.trim().is_empty() {
|
if line.trim().is_empty() {
|
||||||
return Ok(Response::Deny);
|
return Ok(Response::Deny);
|
||||||
}
|
}
|
||||||
let code = Parser::new("", Lexer::new(line)).parse::<Stmt>()?;
|
let code = Parser::new(Lexer::new(line)).parse::<Stmt>()?;
|
||||||
let code = ModuleInliner::new(".").fold_stmt(code);
|
let code = ModuleInliner::new(".").fold_stmt(code);
|
||||||
|
|
||||||
print!("{}", ansi::OUTPUT);
|
print!("{}", ansi::OUTPUT);
|
||||||
@ -75,7 +75,7 @@ pub fn lex(_ctx: &mut ctx::Context) -> ReplResult<()> {
|
|||||||
|
|
||||||
pub fn fmt(_ctx: &mut ctx::Context) -> ReplResult<()> {
|
pub fn fmt(_ctx: &mut ctx::Context) -> ReplResult<()> {
|
||||||
read_and(ansi::BRIGHT_MAGENTA, "cl>", " ?>", |line| {
|
read_and(ansi::BRIGHT_MAGENTA, "cl>", " ?>", |line| {
|
||||||
let mut p = Parser::new("", Lexer::new(line));
|
let mut p = Parser::new(Lexer::new(line));
|
||||||
|
|
||||||
match p.parse::<Stmt>() {
|
match p.parse::<Stmt>() {
|
||||||
Ok(code) => println!("{}{code}{}", ansi::OUTPUT, ansi::RESET),
|
Ok(code) => println!("{}{code}{}", ansi::OUTPUT, ansi::RESET),
|
||||||
|
@ -61,10 +61,8 @@ macro_rules! make_index {($($(#[$meta:meta])* $name:ident),*$(,)?) => {$(
|
|||||||
)*}}
|
)*}}
|
||||||
|
|
||||||
use self::iter::MapIndexIter;
|
use self::iter::MapIndexIter;
|
||||||
use std::{
|
use core::slice::GetManyMutError;
|
||||||
ops::{Index, IndexMut},
|
use std::ops::{Index, IndexMut};
|
||||||
slice::GetDisjointMutError,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use make_index;
|
pub use make_index;
|
||||||
|
|
||||||
@ -105,11 +103,11 @@ impl<V, K: MapIndex> IndexMap<K, V> {
|
|||||||
/// Returns mutable references to many indices at once.
|
/// Returns mutable references to many indices at once.
|
||||||
///
|
///
|
||||||
/// Returns an error if any index is out of bounds, or if the same index was passed twice.
|
/// Returns an error if any index is out of bounds, or if the same index was passed twice.
|
||||||
pub fn get_disjoint_mut<const N: usize>(
|
pub fn get_many_mut<const N: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: [K; N],
|
indices: [K; N],
|
||||||
) -> Result<[&mut V; N], GetDisjointMutError> {
|
) -> Result<[&mut V; N], GetManyMutError> {
|
||||||
self.map.get_disjoint_mut(indices.map(|id| id.get()))
|
self.map.get_many_mut(indices.map(|id| id.get()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over the IndexMap.
|
/// Returns an iterator over the IndexMap.
|
||||||
|
@ -37,8 +37,8 @@ pub mod interned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the internal value as a reference with the interner's lifetime
|
/// Gets the internal value as a reference with the interner's lifetime
|
||||||
pub fn to_ref(&self) -> &'a T {
|
pub fn to_ref(interned: &Self) -> &'a T {
|
||||||
self.value
|
interned.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,17 +264,12 @@ pub mod typed_interner {
|
|||||||
/// A [TypedInterner] hands out [Interned] references for arbitrary types.
|
/// A [TypedInterner] hands out [Interned] references for arbitrary types.
|
||||||
///
|
///
|
||||||
/// See the [module-level documentation](self) for more information.
|
/// See the [module-level documentation](self) for more information.
|
||||||
|
#[derive(Default)]
|
||||||
pub struct TypedInterner<'a, T: Eq + Hash> {
|
pub struct TypedInterner<'a, T: Eq + Hash> {
|
||||||
arena: TypedArena<'a, T>,
|
arena: TypedArena<'a, T>,
|
||||||
keys: RwLock<HashSet<&'a T>>,
|
keys: RwLock<HashSet<&'a T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Eq + Hash> Default for TypedInterner<'a, T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self { arena: Default::default(), keys: Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: Eq + Hash> TypedInterner<'a, T> {
|
impl<'a, T: Eq + Hash> TypedInterner<'a, T> {
|
||||||
/// Creates a new [TypedInterner] backed by the provided [TypedArena]
|
/// Creates a new [TypedInterner] backed by the provided [TypedArena]
|
||||||
pub fn new(arena: TypedArena<'a, T>) -> Self {
|
pub fn new(arena: TypedArena<'a, T>) -> Self {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
//! [im]: index_map::IndexMap
|
//! [im]: index_map::IndexMap
|
||||||
//! [mi]: index_map::MapIndex
|
//! [mi]: index_map::MapIndex
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
#![feature(dropck_eyepatch, decl_macro)]
|
#![feature(dropck_eyepatch, decl_macro, get_many_mut)]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
pub mod intern;
|
pub mod intern;
|
||||||
|
@ -42,6 +42,6 @@ impl Loc {
|
|||||||
impl std::fmt::Display for Loc {
|
impl std::fmt::Display for Loc {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Loc { line, col } = self;
|
let Loc { line, col } = self;
|
||||||
write!(f, "{line}:{col}")
|
write!(f, "{line}:{col}:")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,8 +93,8 @@ use std::{
|
|||||||
/// assert_eq!(Some(&10), v.last());
|
/// assert_eq!(Some(&10), v.last());
|
||||||
/// ```
|
/// ```
|
||||||
pub macro stack {
|
pub macro stack {
|
||||||
($capacity:literal) => {
|
($count:literal) => {
|
||||||
Stack::<_, $capacity>::new()
|
Stack::<_, $count>::new()
|
||||||
},
|
},
|
||||||
($value:expr ; $count:literal) => {{
|
($value:expr ; $count:literal) => {{
|
||||||
let mut stack: Stack<_, $count> = Stack::new();
|
let mut stack: Stack<_, $count> = Stack::new();
|
||||||
@ -103,13 +103,6 @@ pub macro stack {
|
|||||||
}
|
}
|
||||||
stack
|
stack
|
||||||
}},
|
}},
|
||||||
($value:expr ; $count:literal ; $capacity:literal) => {{
|
|
||||||
let mut stack: Stack<_, $capacity> = Stack::new();
|
|
||||||
for _ in 0..$count {
|
|
||||||
stack.push($value)
|
|
||||||
}
|
|
||||||
stack
|
|
||||||
}},
|
|
||||||
($($values:expr),* $(,)?) => {
|
($($values:expr),* $(,)?) => {
|
||||||
Stack::from([$($values),*])
|
Stack::from([$($values),*])
|
||||||
}
|
}
|
||||||
@ -149,14 +142,20 @@ impl<T, const N: usize> Deref for Stack<T, N> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.as_slice()
|
// Safety:
|
||||||
|
// - We have ensured all elements from 0 to len have been initialized
|
||||||
|
// - self.elem[0] came from a reference, and so is aligned to T
|
||||||
|
// unsafe { &*(&self.buf[0..self.len] as *const [_] as *const [T]) }
|
||||||
|
unsafe { slice::from_raw_parts(self.buf.as_ptr().cast(), self.len) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const N: usize> DerefMut for Stack<T, N> {
|
impl<T, const N: usize> DerefMut for Stack<T, N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.as_mut_slice()
|
// Safety:
|
||||||
|
// - See Deref
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.buf.as_mut_ptr().cast(), self.len) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +163,7 @@ impl<T, const N: usize> DerefMut for Stack<T, N> {
|
|||||||
unsafe impl<#[may_dangle] T, const N: usize> Drop for Stack<T, N> {
|
unsafe impl<#[may_dangle] T, const N: usize> Drop for Stack<T, N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Safety: Elements in [0..self.len] are initialized
|
// Safety: We have ensured that all elements in the list are
|
||||||
if std::mem::needs_drop::<T>() {
|
if std::mem::needs_drop::<T>() {
|
||||||
unsafe { core::ptr::drop_in_place(self.as_mut_slice()) };
|
unsafe { core::ptr::drop_in_place(self.as_mut_slice()) };
|
||||||
}
|
}
|
||||||
@ -272,24 +271,18 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an unsafe mutable pointer to the stack's buffer
|
/// Returns an unsafe mutable pointer to the stack's buffer
|
||||||
pub const fn as_mut_ptr(&mut self) -> *mut T {
|
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||||
self.buf.as_mut_ptr().cast()
|
self.buf.as_mut_ptr().cast()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts a slice containing the entire vector
|
/// Extracts a slice containing the entire vector
|
||||||
pub const fn as_slice(&self) -> &[T] {
|
pub fn as_slice(&self) -> &[T] {
|
||||||
// Safety:
|
self
|
||||||
// - We have ensured all elements from 0 to len have been initialized
|
|
||||||
// - self.elem[0] came from a reference, and so is aligned to T
|
|
||||||
// unsafe { &*(&self.buf[0..self.len] as *const [_] as *const [T]) }
|
|
||||||
unsafe { slice::from_raw_parts(self.buf.as_ptr().cast(), self.len) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts a mutable slice containing the entire vector
|
/// Extracts a mutable slice containing the entire vector
|
||||||
pub const fn as_mut_slice(&mut self) -> &mut [T] {
|
pub fn as_mut_slice(&mut self) -> &mut [T] {
|
||||||
// Safety:
|
self
|
||||||
// - See Stack::as_slice
|
|
||||||
unsafe { slice::from_raw_parts_mut(self.buf.as_mut_ptr().cast(), self.len) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the total number of elements the stack can hold
|
/// Returns the total number of elements the stack can hold
|
||||||
@ -362,7 +355,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
/// v.push(3);
|
/// v.push(3);
|
||||||
/// assert_eq!(&[0, 1, 2, 3], v.as_slice());
|
/// assert_eq!(&[0, 1, 2, 3], v.as_slice());
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn push(&mut self, value: T) {
|
pub fn push(&mut self, value: T) {
|
||||||
if self.len >= N {
|
if self.len >= N {
|
||||||
panic!("Attempted to push into full stack")
|
panic!("Attempted to push into full stack")
|
||||||
}
|
}
|
||||||
@ -373,7 +366,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
/// Push a new element onto the end of the stack
|
/// Push a new element onto the end of the stack
|
||||||
///
|
///
|
||||||
/// Returns [`Err(value)`](Result::Err) if the new length would exceed capacity
|
/// Returns [`Err(value)`](Result::Err) if the new length would exceed capacity
|
||||||
pub const fn try_push(&mut self, value: T) -> Result<(), T> {
|
pub fn try_push(&mut self, value: T) -> Result<(), T> {
|
||||||
if self.len >= N {
|
if self.len >= N {
|
||||||
return Err(value);
|
return Err(value);
|
||||||
}
|
}
|
||||||
@ -388,11 +381,8 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
///
|
///
|
||||||
/// len after push must not exceed capacity N
|
/// len after push must not exceed capacity N
|
||||||
#[inline]
|
#[inline]
|
||||||
const unsafe fn push_unchecked(&mut self, value: T) {
|
unsafe fn push_unchecked(&mut self, value: T) {
|
||||||
unsafe {
|
unsafe { ptr::write(self.as_mut_ptr().add(self.len), value) }
|
||||||
// self.buf.get_unchecked_mut(self.len).write(value); // TODO: This is non-const
|
|
||||||
ptr::write(self.as_mut_ptr().add(self.len), value)
|
|
||||||
}
|
|
||||||
self.len += 1; // post inc
|
self.len += 1; // post inc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,14 +402,13 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
/// assert_eq!(Some(0), v.pop());
|
/// assert_eq!(Some(0), v.pop());
|
||||||
/// assert_eq!(None, v.pop());
|
/// assert_eq!(None, v.pop());
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn pop(&mut self) -> Option<T> {
|
pub fn pop(&mut self) -> Option<T> {
|
||||||
if self.len == 0 {
|
if self.len == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.len -= 1;
|
self.len -= 1;
|
||||||
// Safety: MaybeUninit<T> implies ManuallyDrop<T>,
|
// Safety: MaybeUninit<T> implies ManuallyDrop<T>,
|
||||||
// therefore should not get dropped twice
|
// therefore should not get dropped twice
|
||||||
// Some(unsafe { self.buf.get_unchecked_mut(self.len).assume_init_read() })
|
|
||||||
Some(unsafe { ptr::read(self.as_ptr().add(self.len).cast()) })
|
Some(unsafe { ptr::read(self.as_ptr().add(self.len).cast()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,7 +507,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
///
|
///
|
||||||
/// assert_eq!(Ok(()), v.try_insert(0, 0));
|
/// assert_eq!(Ok(()), v.try_insert(0, 0));
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn try_insert(&mut self, index: usize, data: T) -> Result<(), (T, InsertFailed<N>)> {
|
pub fn try_insert(&mut self, index: usize, data: T) -> Result<(), (T, InsertFailed<N>)> {
|
||||||
if index > self.len {
|
if index > self.len {
|
||||||
return Err((data, InsertFailed::Bounds(index)));
|
return Err((data, InsertFailed::Bounds(index)));
|
||||||
}
|
}
|
||||||
@ -534,7 +523,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
/// - index must be less than self.len
|
/// - index must be less than self.len
|
||||||
/// - length after insertion must be <= N
|
/// - length after insertion must be <= N
|
||||||
#[inline]
|
#[inline]
|
||||||
const unsafe fn insert_unchecked(&mut self, index: usize, data: T) {
|
unsafe fn insert_unchecked(&mut self, index: usize, data: T) {
|
||||||
let base = self.as_mut_ptr();
|
let base = self.as_mut_ptr();
|
||||||
|
|
||||||
unsafe { ptr::copy(base.add(index), base.add(index + 1), self.len - index) }
|
unsafe { ptr::copy(base.add(index), base.add(index + 1), self.len - index) }
|
||||||
@ -558,9 +547,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
// Hopefully copy elision takes care of this lmao
|
// Hopefully copy elision takes care of this lmao
|
||||||
while !self.is_empty() {
|
drop(std::mem::take(self))
|
||||||
drop(self.pop());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of elements in the stack
|
/// Returns the number of elements in the stack
|
||||||
@ -570,7 +557,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
///
|
///
|
||||||
/// assert_eq!(5, v.len());
|
/// assert_eq!(5, v.len());
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,7 +572,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
/// assert!(v.is_full());
|
/// assert!(v.is_full());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_full(&self) -> bool {
|
pub fn is_full(&self) -> bool {
|
||||||
self.len >= N
|
self.len >= N
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,7 +587,7 @@ impl<T, const N: usize> Stack<T, N> {
|
|||||||
/// assert!(v.is_empty());
|
/// assert!(v.is_empty());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len == 0
|
self.len == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,7 +625,6 @@ mod tests {
|
|||||||
v.pop();
|
v.pop();
|
||||||
assert_eq!(v.len(), usize::MAX - 1);
|
assert_eq!(v.len(), usize::MAX - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new() {
|
fn new() {
|
||||||
let v: Stack<(), 255> = Stack::new();
|
let v: Stack<(), 255> = Stack::new();
|
||||||
@ -759,19 +745,4 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
std::mem::drop(std::hint::black_box(v));
|
std::mem::drop(std::hint::black_box(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn drop_zst() {
|
|
||||||
struct Droppable;
|
|
||||||
impl Drop for Droppable {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
|
||||||
static V: AtomicU32 = AtomicU32::new(1);
|
|
||||||
eprintln!("{}", V.fetch_add(1, Ordering::Relaxed));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let v = Stack::from([const { Droppable }; 10]);
|
|
||||||
std::mem::drop(v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ pub enum TokenKind {
|
|||||||
Mut, // "mut"
|
Mut, // "mut"
|
||||||
Pub, // "pub"
|
Pub, // "pub"
|
||||||
Return, // "return"
|
Return, // "return"
|
||||||
|
SelfKw, // "self"
|
||||||
SelfTy, // "Self"
|
SelfTy, // "Self"
|
||||||
Static, // "static"
|
Static, // "static"
|
||||||
Struct, // "struct"
|
Struct, // "struct"
|
||||||
@ -106,34 +107,35 @@ impl Display for TokenKind {
|
|||||||
TokenKind::Literal => "literal".fmt(f),
|
TokenKind::Literal => "literal".fmt(f),
|
||||||
TokenKind::Identifier => "identifier".fmt(f),
|
TokenKind::Identifier => "identifier".fmt(f),
|
||||||
|
|
||||||
TokenKind::As => "as".fmt(f),
|
TokenKind::As => "sama".fmt(f),
|
||||||
TokenKind::Break => "break".fmt(f),
|
TokenKind::Break => "pana".fmt(f),
|
||||||
TokenKind::Cl => "cl".fmt(f),
|
TokenKind::Cl => "la".fmt(f),
|
||||||
TokenKind::Const => "const".fmt(f),
|
TokenKind::Const => "kiwen".fmt(f),
|
||||||
TokenKind::Continue => "continue".fmt(f),
|
TokenKind::Continue => "tawa".fmt(f),
|
||||||
TokenKind::Else => "else".fmt(f),
|
TokenKind::Else => "taso".fmt(f),
|
||||||
TokenKind::Enum => "enum".fmt(f),
|
TokenKind::Enum => "kulupu".fmt(f),
|
||||||
TokenKind::False => "false".fmt(f),
|
TokenKind::False => "ike".fmt(f),
|
||||||
TokenKind::Fn => "fn".fmt(f),
|
TokenKind::Fn => "nasin".fmt(f),
|
||||||
TokenKind::For => "for".fmt(f),
|
TokenKind::For => "ale".fmt(f),
|
||||||
TokenKind::If => "if".fmt(f),
|
TokenKind::If => "tan".fmt(f),
|
||||||
TokenKind::Impl => "impl".fmt(f),
|
TokenKind::Impl => "insa".fmt(f),
|
||||||
TokenKind::In => "in".fmt(f),
|
TokenKind::In => "lon".fmt(f),
|
||||||
TokenKind::Let => "let".fmt(f),
|
TokenKind::Let => "poki".fmt(f),
|
||||||
TokenKind::Loop => "loop".fmt(f),
|
TokenKind::Loop => "awen".fmt(f),
|
||||||
TokenKind::Match => "match".fmt(f),
|
TokenKind::Match => "seme".fmt(f),
|
||||||
TokenKind::Mod => "mod".fmt(f),
|
TokenKind::Mod => "selo".fmt(f),
|
||||||
TokenKind::Mut => "mut".fmt(f),
|
TokenKind::Mut => "ante".fmt(f),
|
||||||
TokenKind::Pub => "pub".fmt(f),
|
TokenKind::Pub => "lukin".fmt(f),
|
||||||
TokenKind::Return => "return".fmt(f),
|
TokenKind::Return => "pini".fmt(f),
|
||||||
TokenKind::SelfTy => "Self".fmt(f),
|
TokenKind::SelfKw => "mi".fmt(f),
|
||||||
TokenKind::Static => "static".fmt(f),
|
TokenKind::SelfTy => "Mi".fmt(f),
|
||||||
TokenKind::Struct => "struct".fmt(f),
|
TokenKind::Static => "mute".fmt(f),
|
||||||
TokenKind::Super => "super".fmt(f),
|
TokenKind::Struct => "lipu".fmt(f),
|
||||||
TokenKind::True => "true".fmt(f),
|
TokenKind::Super => "mama".fmt(f),
|
||||||
TokenKind::Type => "type".fmt(f),
|
TokenKind::True => "pona".fmt(f),
|
||||||
TokenKind::Use => "use".fmt(f),
|
TokenKind::Type => "ijo".fmt(f),
|
||||||
TokenKind::While => "while".fmt(f),
|
TokenKind::Use => "jo".fmt(f),
|
||||||
|
TokenKind::While => "lawa".fmt(f),
|
||||||
|
|
||||||
TokenKind::LCurly => "{".fmt(f),
|
TokenKind::LCurly => "{".fmt(f),
|
||||||
TokenKind::RCurly => "}".fmt(f),
|
TokenKind::RCurly => "}".fmt(f),
|
||||||
@ -198,34 +200,35 @@ impl FromStr for TokenKind {
|
|||||||
/// Parses a string s to return a Keyword
|
/// Parses a string s to return a Keyword
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(match s {
|
Ok(match s {
|
||||||
"as" => Self::As,
|
"as" | "sama" => Self::As,
|
||||||
"break" => Self::Break,
|
"break" | "pana" => Self::Break,
|
||||||
"cl" => Self::Cl,
|
"cl" | "la" => Self::Cl,
|
||||||
"const" => Self::Const,
|
"const" | "kiwen" => Self::Const,
|
||||||
"continue" => Self::Continue,
|
"continue" | "tawa" => Self::Continue,
|
||||||
"else" => Self::Else,
|
"else" | "taso" => Self::Else,
|
||||||
"enum" => Self::Enum,
|
"enum" | "kulupu" => Self::Enum,
|
||||||
"false" => Self::False,
|
"false" | "ike" => Self::False,
|
||||||
"fn" => Self::Fn,
|
"fn" | "nasin" => Self::Fn,
|
||||||
"for" => Self::For,
|
"for" | "ale" => Self::For,
|
||||||
"if" => Self::If,
|
"if" | "tan" => Self::If,
|
||||||
"impl" => Self::Impl,
|
"impl" | "insa" => Self::Impl,
|
||||||
"in" => Self::In,
|
"in" | "lon" => Self::In,
|
||||||
"let" => Self::Let,
|
"let" | "poki" => Self::Let,
|
||||||
"loop" => Self::Loop,
|
"loop" | "awen" => Self::Loop,
|
||||||
"match" => Self::Match,
|
"match" | "seme" => Self::Match,
|
||||||
"mod" => Self::Mod,
|
"mod" | "selo" => Self::Mod,
|
||||||
"mut" => Self::Mut,
|
"mut" | "ante" => Self::Mut,
|
||||||
"pub" => Self::Pub,
|
"pub" | "lukin" => Self::Pub,
|
||||||
"return" => Self::Return,
|
"return" | "pini" => Self::Return,
|
||||||
"Self" => Self::SelfTy,
|
"self" | "mi" => Self::SelfKw,
|
||||||
"static" => Self::Static,
|
"Self" | "Mi" => Self::SelfTy,
|
||||||
"struct" => Self::Struct,
|
"static" | "mute" => Self::Static,
|
||||||
"super" => Self::Super,
|
"struct" | "lipu" => Self::Struct,
|
||||||
"true" => Self::True,
|
"super" | "mama" => Self::Super,
|
||||||
"type" => Self::Type,
|
"true" | "pona" => Self::True,
|
||||||
"use" => Self::Use,
|
"type" | "ijo" => Self::Type,
|
||||||
"while" => Self::While,
|
"use" | "jo" => Self::Use,
|
||||||
|
"while" | "lawa" => Self::While,
|
||||||
_ => Err(())?,
|
_ => Err(())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,12 @@
|
|||||||
use cl_typeck::{
|
use cl_typeck::{entry::Entry, stage::*, table::Table, type_expression::TypeExpression};
|
||||||
entry::Entry,
|
|
||||||
stage::{
|
|
||||||
infer::{engine::InferenceEngine, error::InferenceError, inference::Inference},
|
|
||||||
*,
|
|
||||||
},
|
|
||||||
table::Table,
|
|
||||||
type_expression::TypeExpression,
|
|
||||||
};
|
|
||||||
|
|
||||||
use cl_ast::{
|
use cl_ast::{
|
||||||
Expr, Path, Stmt, Ty,
|
|
||||||
ast_visitor::{Fold, Visit},
|
ast_visitor::{Fold, Visit},
|
||||||
desugar::*,
|
desugar::*,
|
||||||
|
Stmt, Ty,
|
||||||
};
|
};
|
||||||
use cl_lexer::Lexer;
|
use cl_lexer::Lexer;
|
||||||
use cl_parser::{Parser, inliner::ModuleInliner};
|
use cl_parser::{inliner::ModuleInliner, Parser};
|
||||||
use cl_structures::intern::string_interner::StringInterner;
|
use cl_structures::intern::string_interner::StringInterner;
|
||||||
use repline::{error::Error as RlError, prebaked::*};
|
use repline::{error::Error as RlError, prebaked::*};
|
||||||
use std::{
|
use std::{
|
||||||
@ -42,7 +34,7 @@ const C_LISTING: &str = "\x1b[38;5;117m";
|
|||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut prj = Table::default();
|
let mut prj = Table::default();
|
||||||
|
|
||||||
let mut parser = Parser::new("PREAMBLE", Lexer::new(PREAMBLE));
|
let mut parser = Parser::new(Lexer::new(PREAMBLE));
|
||||||
let code = match parser.parse() {
|
let code = match parser.parse() {
|
||||||
Ok(code) => code,
|
Ok(code) => code,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -52,15 +44,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
};
|
};
|
||||||
// This code is special - it gets loaded from a hard-coded project directory (for now)
|
// This code is special - it gets loaded from a hard-coded project directory (for now)
|
||||||
let code = inline_modules(code, concat!(env!("CARGO_MANIFEST_DIR"), "/../../stdlib"));
|
let code = inline_modules(code, concat!(env!("CARGO_MANIFEST_DIR"), "/../../stdlib"));
|
||||||
let code = cl_ast::desugar::WhileElseDesugar.fold_file(code);
|
|
||||||
Populator::new(&mut prj).visit_file(interned(code));
|
Populator::new(&mut prj).visit_file(interned(code));
|
||||||
|
|
||||||
for arg in std::env::args().skip(1) {
|
|
||||||
import_file(&mut prj, arg)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve_all(&mut prj)?;
|
|
||||||
|
|
||||||
main_menu(&mut prj)?;
|
main_menu(&mut prj)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -68,8 +53,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
fn main_menu(prj: &mut Table) -> Result<(), RlError> {
|
fn main_menu(prj: &mut Table) -> Result<(), RlError> {
|
||||||
banner();
|
banner();
|
||||||
read_and(C_MAIN, "mu>", "? >", |line| {
|
read_and(C_MAIN, "mu>", "? >", |line| {
|
||||||
for line in line.trim().split_ascii_whitespace() {
|
match line.trim() {
|
||||||
match line {
|
|
||||||
"c" | "code" => enter_code(prj)?,
|
"c" | "code" => enter_code(prj)?,
|
||||||
"clear" => clear()?,
|
"clear" => clear()?,
|
||||||
"d" | "desugar" => live_desugar()?,
|
"d" | "desugar" => live_desugar()?,
|
||||||
@ -80,8 +64,6 @@ fn main_menu(prj: &mut Table) -> Result<(), RlError> {
|
|||||||
"q" | "query" => query_type_expression(prj)?,
|
"q" | "query" => query_type_expression(prj)?,
|
||||||
"r" | "resolve" => resolve_all(prj)?,
|
"r" | "resolve" => resolve_all(prj)?,
|
||||||
"s" | "strings" => print_strings(),
|
"s" | "strings" => print_strings(),
|
||||||
"a" | "all" => infer_all(prj)?,
|
|
||||||
"t" | "test" => infer_expression(prj)?,
|
|
||||||
"h" | "help" | "" => {
|
"h" | "help" | "" => {
|
||||||
println!(
|
println!(
|
||||||
"Valid commands are:
|
"Valid commands are:
|
||||||
@ -100,7 +82,6 @@ fn main_menu(prj: &mut Table) -> Result<(), RlError> {
|
|||||||
}
|
}
|
||||||
_ => Err(r#"Invalid command. Type "help" to see the list of valid commands."#)?,
|
_ => Err(r#"Invalid command. Type "help" to see the list of valid commands."#)?,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(Response::Accept)
|
Ok(Response::Accept)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -110,7 +91,7 @@ fn enter_code(prj: &mut Table) -> Result<(), RlError> {
|
|||||||
if line.trim().is_empty() {
|
if line.trim().is_empty() {
|
||||||
return Ok(Response::Break);
|
return Ok(Response::Break);
|
||||||
}
|
}
|
||||||
let code = Parser::new("", Lexer::new(line)).parse()?;
|
let code = Parser::new(Lexer::new(line)).parse()?;
|
||||||
let code = inline_modules(code, "");
|
let code = inline_modules(code, "");
|
||||||
let code = WhileElseDesugar.fold_file(code);
|
let code = WhileElseDesugar.fold_file(code);
|
||||||
|
|
||||||
@ -121,12 +102,9 @@ fn enter_code(prj: &mut Table) -> Result<(), RlError> {
|
|||||||
|
|
||||||
fn live_desugar() -> Result<(), RlError> {
|
fn live_desugar() -> Result<(), RlError> {
|
||||||
read_and(C_RESV, "se>", "? >", |line| {
|
read_and(C_RESV, "se>", "? >", |line| {
|
||||||
let code = Parser::new("", Lexer::new(line)).parse::<Stmt>()?;
|
let code = Parser::new(Lexer::new(line)).parse::<Stmt>()?;
|
||||||
println!("Raw, as parsed:\n{C_LISTING}{code}\x1b[0m");
|
println!("Raw, as parsed:\n{C_LISTING}{code}\x1b[0m");
|
||||||
|
|
||||||
let code = ConstantFolder.fold_stmt(code);
|
|
||||||
println!("ConstantFolder\n{C_LISTING}{code}\x1b[0m");
|
|
||||||
|
|
||||||
let code = SquashGroups.fold_stmt(code);
|
let code = SquashGroups.fold_stmt(code);
|
||||||
println!("SquashGroups\n{C_LISTING}{code}\x1b[0m");
|
println!("SquashGroups\n{C_LISTING}{code}\x1b[0m");
|
||||||
|
|
||||||
@ -149,48 +127,14 @@ fn query_type_expression(prj: &mut Table) -> Result<(), RlError> {
|
|||||||
if line.trim().is_empty() {
|
if line.trim().is_empty() {
|
||||||
return Ok(Response::Break);
|
return Ok(Response::Break);
|
||||||
}
|
}
|
||||||
// A query is comprised of a Ty and a relative Path
|
// parse it as a path, and convert the path into a borrowed path
|
||||||
let mut p = Parser::new("", Lexer::new(line));
|
let ty: Ty = Parser::new(Lexer::new(line)).parse()?;
|
||||||
let ty: Ty = p.parse()?;
|
|
||||||
let path: Path = p
|
|
||||||
.parse()
|
|
||||||
.map(|p| Path { absolute: false, ..p })
|
|
||||||
.unwrap_or_default();
|
|
||||||
let id = ty.evaluate(prj, prj.root())?;
|
let id = ty.evaluate(prj, prj.root())?;
|
||||||
let id = path.evaluate(prj, id)?;
|
|
||||||
pretty_handle(id.to_entry(prj))?;
|
pretty_handle(id.to_entry(prj))?;
|
||||||
Ok(Response::Accept)
|
Ok(Response::Accept)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn infer_expression(prj: &mut Table) -> Result<(), RlError> {
|
|
||||||
read_and(C_RESV, "ex>", "!?>", |line| {
|
|
||||||
if line.trim().is_empty() {
|
|
||||||
return Ok(Response::Break);
|
|
||||||
}
|
|
||||||
let mut p = Parser::new("", Lexer::new(line));
|
|
||||||
let e: Expr = p.parse()?;
|
|
||||||
let mut inf = InferenceEngine::new(prj, prj.root());
|
|
||||||
let ty = match exp_terned(e).infer(&mut inf) {
|
|
||||||
Ok(ty) => ty,
|
|
||||||
Err(e) => match e {
|
|
||||||
InferenceError::Mismatch(a, b) => {
|
|
||||||
eprintln!("Mismatched types: {}, {}", prj.entry(a), prj.entry(b));
|
|
||||||
return Ok(Response::Deny);
|
|
||||||
}
|
|
||||||
InferenceError::Recursive(a, b) => {
|
|
||||||
eprintln!("Recursive types: {}, {}", prj.entry(a), prj.entry(b));
|
|
||||||
return Ok(Response::Deny);
|
|
||||||
}
|
|
||||||
e => Err(e)?,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
eprintln!("--> {}", prj.entry(ty));
|
|
||||||
Ok(Response::Accept)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_by_id(prj: &mut Table) -> Result<(), RlError> {
|
fn get_by_id(prj: &mut Table) -> Result<(), RlError> {
|
||||||
use cl_parser::parser::Parse;
|
use cl_parser::parser::Parse;
|
||||||
use cl_structures::index_map::MapIndex;
|
use cl_structures::index_map::MapIndex;
|
||||||
@ -199,7 +143,7 @@ fn get_by_id(prj: &mut Table) -> Result<(), RlError> {
|
|||||||
if line.trim().is_empty() {
|
if line.trim().is_empty() {
|
||||||
return Ok(Response::Break);
|
return Ok(Response::Break);
|
||||||
}
|
}
|
||||||
let mut parser = Parser::new("", Lexer::new(line));
|
let mut parser = Parser::new(Lexer::new(line));
|
||||||
let def_id = match Parse::parse(&mut parser)? {
|
let def_id = match Parse::parse(&mut parser)? {
|
||||||
cl_ast::Literal::Int(int) => int as _,
|
cl_ast::Literal::Int(int) => int as _,
|
||||||
other => Err(format!("Expected integer, got {other}"))?,
|
other => Err(format!("Expected integer, got {other}"))?,
|
||||||
@ -243,24 +187,6 @@ fn resolve_all(table: &mut Table) -> Result<(), Box<dyn Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_all(table: &mut Table) -> Result<(), Box<dyn Error>> {
|
|
||||||
for (id, error) in InferenceEngine::new(table, table.root()).infer_all() {
|
|
||||||
match error {
|
|
||||||
InferenceError::Mismatch(a, b) => {
|
|
||||||
eprint!("Mismatched types: {}, {}", table.entry(a), table.entry(b));
|
|
||||||
}
|
|
||||||
InferenceError::Recursive(a, b) => {
|
|
||||||
eprint!("Recursive types: {}, {}", table.entry(a), table.entry(b));
|
|
||||||
}
|
|
||||||
e => eprint!("{e}"),
|
|
||||||
}
|
|
||||||
eprintln!(" in {} ({id})", id.to_entry(table))
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("...Inferred!");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list_types(table: &mut Table) {
|
fn list_types(table: &mut Table) {
|
||||||
for handle in table.debug_entry_iter() {
|
for handle in table.debug_entry_iter() {
|
||||||
let id = handle.id();
|
let id = handle.id();
|
||||||
@ -270,32 +196,6 @@ fn list_types(table: &mut Table) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_file(table: &mut Table, path: impl AsRef<std::path::Path>) -> Result<(), Box<dyn Error>> {
|
|
||||||
let Ok(file) = std::fs::read_to_string(path.as_ref()) else {
|
|
||||||
for file in std::fs::read_dir(path)? {
|
|
||||||
println!("{}", file?.path().display())
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut parser = Parser::new("", Lexer::new(&file));
|
|
||||||
let code = match parser.parse() {
|
|
||||||
Ok(code) => inline_modules(
|
|
||||||
code,
|
|
||||||
PathBuf::from(path.as_ref()).parent().unwrap_or("".as_ref()),
|
|
||||||
),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{C_ERROR}{}:{e}\x1b[0m", path.as_ref().display());
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let code = cl_ast::desugar::WhileElseDesugar.fold_file(code);
|
|
||||||
Populator::new(table).visit_file(interned(code));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn import_files(table: &mut Table) -> Result<(), RlError> {
|
fn import_files(table: &mut Table) -> Result<(), RlError> {
|
||||||
read_and(C_RESV, "fi>", "? >", |line| {
|
read_and(C_RESV, "fi>", "? >", |line| {
|
||||||
let line = line.trim();
|
let line = line.trim();
|
||||||
@ -309,7 +209,7 @@ fn import_files(table: &mut Table) -> Result<(), RlError> {
|
|||||||
return Ok(Response::Accept);
|
return Ok(Response::Accept);
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut parser = Parser::new("", Lexer::new(&file));
|
let mut parser = Parser::new(Lexer::new(&file));
|
||||||
let code = match parser.parse() {
|
let code = match parser.parse() {
|
||||||
Ok(code) => inline_modules(code, PathBuf::from(line).parent().unwrap_or("".as_ref())),
|
Ok(code) => inline_modules(code, PathBuf::from(line).parent().unwrap_or("".as_ref())),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -420,18 +320,9 @@ fn banner() {
|
|||||||
|
|
||||||
/// Interns a [File](cl_ast::File), returning a static reference to it.
|
/// Interns a [File](cl_ast::File), returning a static reference to it.
|
||||||
fn interned(file: cl_ast::File) -> &'static cl_ast::File {
|
fn interned(file: cl_ast::File) -> &'static cl_ast::File {
|
||||||
use cl_structures::intern::typed_interner::TypedInterner;
|
use cl_structures::intern::{interned::Interned, typed_interner::TypedInterner};
|
||||||
static INTERNER: LazyLock<TypedInterner<'static, cl_ast::File>> =
|
static INTERNER: LazyLock<TypedInterner<'static, cl_ast::File>> =
|
||||||
LazyLock::new(Default::default);
|
LazyLock::new(Default::default);
|
||||||
|
|
||||||
INTERNER.get_or_insert(file).to_ref()
|
Interned::to_ref(&INTERNER.get_or_insert(file))
|
||||||
}
|
|
||||||
|
|
||||||
/// Interns an [Expr](cl_ast::Expr), returning a static reference to it.
|
|
||||||
fn exp_terned(expr: cl_ast::Expr) -> &'static cl_ast::Expr {
|
|
||||||
use cl_structures::intern::typed_interner::TypedInterner;
|
|
||||||
static INTERNER: LazyLock<TypedInterner<'static, cl_ast::Expr>> =
|
|
||||||
LazyLock::new(Default::default);
|
|
||||||
|
|
||||||
INTERNER.get_or_insert(expr).to_ref()
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use cl_ast::{Expr, Meta, PathPart, Sym};
|
use cl_ast::{Meta, PathPart, Sym};
|
||||||
use cl_structures::span::Span;
|
use cl_structures::span::Span;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -46,15 +46,15 @@ impl<'t, 'a> Entry<'t, 'a> {
|
|||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &'t Table<'a> {
|
pub fn inner(&self) -> &Table<'a> {
|
||||||
self.table
|
self.table
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn with_id(&self, id: Handle) -> Entry<'t, 'a> {
|
pub const fn with_id(&self, id: Handle) -> Entry<'_, 'a> {
|
||||||
Self { table: self.table, id }
|
Self { table: self.table, id }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nav(&self, path: &[PathPart]) -> Option<Entry<'t, 'a>> {
|
pub fn nav(&self, path: &[PathPart]) -> Option<Entry<'_, 'a>> {
|
||||||
Some(Entry { id: self.table.nav(self.id, path)?, table: self.table })
|
Some(Entry { id: self.table.nav(self.id, path)?, table: self.table })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,31 +62,27 @@ impl<'t, 'a> Entry<'t, 'a> {
|
|||||||
self.table.root()
|
self.table.root()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> Option<&'t NodeKind> {
|
pub fn kind(&self) -> Option<&NodeKind> {
|
||||||
self.table.kind(self.id)
|
self.table.kind(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent(&self) -> Option<Entry<'t, 'a>> {
|
pub fn parent(&self) -> Option<Entry<'_, 'a>> {
|
||||||
Some(Entry { id: *self.table.parent(self.id)?, ..*self })
|
Some(Entry { id: *self.table.parent(self.id)?, ..*self })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn children(&self) -> Option<&'t HashMap<Sym, Handle>> {
|
pub fn children(&self) -> Option<&HashMap<Sym, Handle>> {
|
||||||
self.table.children(self.id)
|
self.table.children(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imports(&self) -> Option<&'t HashMap<Sym, Handle>> {
|
pub fn imports(&self) -> Option<&HashMap<Sym, Handle>> {
|
||||||
self.table.imports(self.id)
|
self.table.imports(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bodies(&self) -> Option<&'a Expr> {
|
pub fn ty(&self) -> Option<&TypeKind> {
|
||||||
self.table.body(self.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ty(&self) -> Option<&'t TypeKind> {
|
|
||||||
self.table.ty(self.id)
|
self.table.ty(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn span(&self) -> Option<&'t Span> {
|
pub fn span(&self) -> Option<&Span> {
|
||||||
self.table.span(self.id)
|
self.table.span(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +90,7 @@ impl<'t, 'a> Entry<'t, 'a> {
|
|||||||
self.table.meta(self.id)
|
self.table.meta(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source(&self) -> Option<&'t Source<'a>> {
|
pub fn source(&self) -> Option<&Source<'a>> {
|
||||||
self.table.source(self.id)
|
self.table.source(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,10 +154,6 @@ impl<'t, 'a> EntryMut<'t, 'a> {
|
|||||||
self.table.add_child(self.id, name, child)
|
self.table.add_child(self.id, name, child)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_body(&mut self, body: &'a Expr) -> Option<&'a Expr> {
|
|
||||||
self.table.set_body(self.id, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_ty(&mut self, kind: TypeKind) -> Option<TypeKind> {
|
pub fn set_ty(&mut self, kind: TypeKind) -> Option<TypeKind> {
|
||||||
self.table.set_ty(self.id, kind)
|
self.table.set_ty(self.id, kind)
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,8 @@ impl fmt::Display for Entry<'_, '_> {
|
|||||||
|
|
||||||
if let Some(ty) = self.ty() {
|
if let Some(ty) = self.ty() {
|
||||||
match ty {
|
match ty {
|
||||||
TypeKind::Inferred => write!(f, "<_{}>", self.id),
|
|
||||||
TypeKind::Variable => write!(f, "<?{}>", self.id),
|
|
||||||
TypeKind::Instance(id) => write!(f, "{}", self.with_id(*id)),
|
TypeKind::Instance(id) => write!(f, "{}", self.with_id(*id)),
|
||||||
TypeKind::Primitive(kind) => write!(f, "{kind}"),
|
TypeKind::Intrinsic(kind) => write!(f, "{kind}"),
|
||||||
TypeKind::Adt(adt) => write_adt(adt, self, f),
|
TypeKind::Adt(adt) => write_adt(adt, self, f),
|
||||||
&TypeKind::Ref(id) => {
|
&TypeKind::Ref(id) => {
|
||||||
f.write_str("&")?;
|
f.write_str("&")?;
|
||||||
@ -66,10 +64,13 @@ fn write_adt(adt: &Adt, h: &Entry, f: &mut impl Write) -> fmt::Result {
|
|||||||
let mut variants = variants.iter();
|
let mut variants = variants.iter();
|
||||||
separate(", ", || {
|
separate(", ", || {
|
||||||
variants.next().map(|(name, def)| {
|
variants.next().map(|(name, def)| {
|
||||||
move |f: &mut Delimit<_>| {
|
move |f: &mut Delimit<_>| match def {
|
||||||
|
Some(def) => {
|
||||||
write!(f, "{name}: ")?;
|
write!(f, "{name}: ")?;
|
||||||
write_name_or(h.with_id(*def), f)
|
write_name_or(h.with_id(*def), f)
|
||||||
}
|
}
|
||||||
|
None => write!(f, "{name}"),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})(f.delimit_with("enum {", "}"))
|
})(f.delimit_with("enum {", "}"))
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ impl Source<'_> {
|
|||||||
match self {
|
match self {
|
||||||
Source::Root => None,
|
Source::Root => None,
|
||||||
Source::Module(v) => Some(v.name),
|
Source::Module(v) => Some(v.name),
|
||||||
Source::Alias(v) => Some(v.name),
|
Source::Alias(v) => Some(v.to),
|
||||||
Source::Enum(v) => Some(v.name),
|
Source::Enum(v) => Some(v.name),
|
||||||
Source::Variant(v) => Some(v.name),
|
Source::Variant(v) => Some(v.name),
|
||||||
Source::Struct(v) => Some(v.name),
|
Source::Struct(v) => Some(v.name),
|
||||||
|
@ -13,9 +13,9 @@ use cl_ast::*;
|
|||||||
pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
|
pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
|
||||||
if let Some(meta) = table.meta(node) {
|
if let Some(meta) = table.meta(node) {
|
||||||
for meta @ Meta { name, kind } in meta {
|
for meta @ Meta { name, kind } in meta {
|
||||||
if let ("lang", MetaKind::Equals(Literal::String(s))) = (&**name, kind) {
|
if let ("intrinsic", MetaKind::Equals(Literal::String(s))) = (&**name, kind) {
|
||||||
let kind =
|
let kind =
|
||||||
TypeKind::Primitive(s.parse().map_err(|_| Error::BadMeta(meta.clone()))?);
|
TypeKind::Intrinsic(s.parse().map_err(|_| Error::BadMeta(meta.clone()))?);
|
||||||
table.set_ty(node, kind);
|
table.set_ty(node, kind);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
|
|||||||
Source::Module(_) => Ok(()),
|
Source::Module(_) => Ok(()),
|
||||||
Source::Alias(a) => cat_alias(table, node, a),
|
Source::Alias(a) => cat_alias(table, node, a),
|
||||||
Source::Enum(e) => cat_enum(table, node, e),
|
Source::Enum(e) => cat_enum(table, node, e),
|
||||||
Source::Variant(v) => cat_variant(table, node, v),
|
Source::Variant(_) => Ok(()),
|
||||||
Source::Struct(s) => cat_struct(table, node, s),
|
Source::Struct(s) => cat_struct(table, node, s),
|
||||||
Source::Const(c) => cat_const(table, node, c),
|
Source::Const(c) => cat_const(table, node, c),
|
||||||
Source::Static(s) => cat_static(table, node, s),
|
Source::Static(s) => cat_static(table, node, s),
|
||||||
@ -65,14 +65,14 @@ fn cat_alias(table: &mut Table, node: Handle, a: &Alias) -> CatResult<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cat_struct(table: &mut Table, node: Handle, s: &Struct) -> CatResult<()> {
|
fn cat_struct(table: &mut Table, node: Handle, s: &Struct) -> CatResult<()> {
|
||||||
let Struct { name: _, gens: _, kind } = s;
|
let parent = parent(table, node);
|
||||||
// TODO: Generics
|
let Struct { name: _, kind } = s;
|
||||||
let kind = match kind {
|
let kind = match kind {
|
||||||
StructKind::Empty => TypeKind::Adt(Adt::UnitStruct),
|
StructKind::Empty => TypeKind::Adt(Adt::UnitStruct),
|
||||||
StructKind::Tuple(types) => {
|
StructKind::Tuple(types) => {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
for ty in types {
|
for ty in types {
|
||||||
out.push((Visibility::Public, ty.evaluate(table, node)?))
|
out.push((Visibility::Public, ty.evaluate(table, parent)?))
|
||||||
}
|
}
|
||||||
TypeKind::Adt(Adt::TupleStruct(out))
|
TypeKind::Adt(Adt::TupleStruct(out))
|
||||||
}
|
}
|
||||||
@ -98,56 +98,51 @@ fn cat_member(
|
|||||||
Ok((*name, *vis, ty.evaluate(table, node)?))
|
Ok((*name, *vis, ty.evaluate(table, node)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult<()> {
|
fn cat_enum<'a>(table: &mut Table<'a>, node: Handle, e: &'a Enum) -> CatResult<()> {
|
||||||
let Enum { name: _, gens: _, variants: _ } = e;
|
let Enum { name: _, kind } = e;
|
||||||
|
let kind = match kind {
|
||||||
|
EnumKind::NoVariants => TypeKind::Adt(Adt::Enum(vec![])),
|
||||||
|
EnumKind::Variants(variants) => {
|
||||||
|
let mut out_vars = vec![];
|
||||||
|
for v in variants {
|
||||||
|
out_vars.push(cat_variant(table, node, v)?)
|
||||||
|
}
|
||||||
|
TypeKind::Adt(Adt::Enum(out_vars))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// table.set_ty(node, kind);
|
table.set_ty(node, kind);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatResult<()> {
|
fn cat_variant<'a>(
|
||||||
let Variant { name, kind, body } = v;
|
table: &mut Table<'a>,
|
||||||
let parent = table.parent(node).copied().unwrap_or(table.root());
|
node: Handle,
|
||||||
table.add_child(parent, *name, node);
|
v: &'a Variant,
|
||||||
match (kind, body) {
|
) -> CatResult<(Sym, Option<Handle>)> {
|
||||||
(StructKind::Empty, None) => {
|
let parent = parent(table, node);
|
||||||
table.set_ty(node, TypeKind::Adt(Adt::UnitStruct));
|
let Variant { name, kind } = v;
|
||||||
Ok(())
|
match kind {
|
||||||
|
VariantKind::Plain => Ok((*name, None)),
|
||||||
|
VariantKind::CLike(c) => todo!("enum-variant constant {c}"),
|
||||||
|
VariantKind::Tuple(ty) => {
|
||||||
|
let ty = ty
|
||||||
|
.evaluate(table, parent)
|
||||||
|
.map_err(|e| Error::TypeEval(e, " while categorizing a variant"))?;
|
||||||
|
Ok((*name, Some(ty)))
|
||||||
}
|
}
|
||||||
(StructKind::Empty, Some(c)) => {
|
VariantKind::Struct(members) => {
|
||||||
table.set_body(node, c);
|
|
||||||
table.set_ty(node, TypeKind::Adt(Adt::UnitStruct));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(StructKind::Tuple(ty), None) => {
|
|
||||||
let ty = TypeKind::Adt(Adt::TupleStruct(
|
|
||||||
ty.iter()
|
|
||||||
.map(|ty| ty.evaluate(table, node).map(|ty| (Visibility::Public, ty)))
|
|
||||||
.collect::<Result<_, _>>()?,
|
|
||||||
));
|
|
||||||
table.set_ty(node, ty);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(StructKind::Struct(members), None) => {
|
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
for StructMember { vis, name, ty } in members {
|
for m in members {
|
||||||
let ty = ty.evaluate(table, node)?;
|
out.push(cat_member(table, node, m)?)
|
||||||
out.push((*name, *vis, ty));
|
|
||||||
|
|
||||||
let mut this = node.to_entry_mut(table);
|
|
||||||
let mut child = this.new_entry(NodeKind::Type);
|
|
||||||
child.set_source(Source::Variant(v));
|
|
||||||
child.set_ty(TypeKind::Instance(ty));
|
|
||||||
|
|
||||||
let child = child.id();
|
|
||||||
this.add_child(*name, child);
|
|
||||||
}
|
}
|
||||||
|
let kind = TypeKind::Adt(Adt::Struct(out));
|
||||||
|
|
||||||
table.set_ty(node, TypeKind::Adt(Adt::Struct(out)));
|
let mut h = node.to_entry_mut(table);
|
||||||
Ok(())
|
let mut variant = h.new_entry(NodeKind::Type);
|
||||||
}
|
variant.set_source(Source::Variant(v));
|
||||||
(_, Some(body)) => {
|
variant.set_ty(kind);
|
||||||
panic!("Unexpected body `{body}` in enum variant `{v}`")
|
Ok((*name, Some(variant.id())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,9 +168,10 @@ fn cat_static(table: &mut Table, node: Handle, s: &Static) -> CatResult<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cat_function(table: &mut Table, node: Handle, f: &Function) -> CatResult<()> {
|
fn cat_function(table: &mut Table, node: Handle, f: &Function) -> CatResult<()> {
|
||||||
|
let parent = parent(table, node);
|
||||||
let kind = TypeKind::Instance(
|
let kind = TypeKind::Instance(
|
||||||
f.sign
|
f.sign
|
||||||
.evaluate(table, node)
|
.evaluate(table, parent)
|
||||||
.map_err(|e| Error::TypeEval(e, " while categorizing a function"))?,
|
.map_err(|e| Error::TypeEval(e, " while categorizing a function"))?,
|
||||||
);
|
);
|
||||||
table.set_ty(node, kind);
|
table.set_ty(node, kind);
|
||||||
@ -210,6 +206,7 @@ type CatResult<T> = Result<T, Error>;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
BadMeta(Meta),
|
BadMeta(Meta),
|
||||||
|
Recursive(Handle),
|
||||||
TypeEval(TypeEval, &'static str),
|
TypeEval(TypeEval, &'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +219,10 @@ impl From<TypeEval> for Error {
|
|||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::BadMeta(meta) => write!(f, "Unknown attribute: #[{meta}]"),
|
Error::BadMeta(meta) => write!(f, "Unknown meta attribute: #[{meta}]"),
|
||||||
|
Error::Recursive(id) => {
|
||||||
|
write!(f, "Encountered recursive type without indirection: {id}")
|
||||||
|
}
|
||||||
Error::TypeEval(e, during) => write!(f, "{e}{during}"),
|
Error::TypeEval(e, during) => write!(f, "{e}{during}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,244 @@
|
|||||||
//! [1]: https://github.com/tcr/rust-hindley-milner/
|
//! [1]: https://github.com/tcr/rust-hindley-milner/
|
||||||
//! [2]: https://github.com/rob-smallshire/hindley-milner-python
|
//! [2]: https://github.com/rob-smallshire/hindley-milner-python
|
||||||
|
|
||||||
pub mod engine;
|
use cl_ast::Sym;
|
||||||
|
use core::fmt;
|
||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
pub mod inference;
|
/*
|
||||||
|
Types in Conlang:
|
||||||
|
- Never type: !
|
||||||
|
- type !
|
||||||
|
- for<A> ! -> A
|
||||||
|
- Primitive types: bool, i32, (), ...
|
||||||
|
- type bool; ...
|
||||||
|
- Reference types: &T, *T
|
||||||
|
- for<T> type ref<T>; for<T> type ptr<T>
|
||||||
|
- Slice type: [T]
|
||||||
|
- for<T> type slice<T>
|
||||||
|
- Array type: [T;usize]
|
||||||
|
- for<T> type array<T, instanceof<usize>>
|
||||||
|
- Tuple type: (T, ...Z)
|
||||||
|
- for<T, ..> type tuple<T, ..> // on a per-case basis!
|
||||||
|
- Funct type: fn Tuple -> R
|
||||||
|
- for<T, R> type T -> R // on a per-case basis!
|
||||||
|
*/
|
||||||
|
|
||||||
pub mod error;
|
/// A refcounted [Type]
|
||||||
|
pub type RcType = Rc<Type>;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Variable {
|
||||||
|
pub instance: RefCell<Option<RcType>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Operator {
|
||||||
|
name: Sym,
|
||||||
|
types: RefCell<Vec<RcType>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [Type::Variable] or [Type::Operator]:
|
||||||
|
/// - A [Type::Variable] can be either bound or unbound (instance: Some(_) | None)
|
||||||
|
/// - A [Type::Operator] has a name (used to identify the operator) and a list of types.
|
||||||
|
///
|
||||||
|
/// A type which contains unbound variables is considered "generic" (see
|
||||||
|
/// [`Type::is_generic()`]).
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Type {
|
||||||
|
Variable(Variable),
|
||||||
|
Operator(Operator),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
/// Creates a new unbound [type variable](Type::Variable)
|
||||||
|
pub fn new_var() -> RcType {
|
||||||
|
Rc::new(Self::Variable(Variable { instance: RefCell::new(None) }))
|
||||||
|
}
|
||||||
|
/// Creates a variable that is a new instance of another [Type]
|
||||||
|
pub fn new_inst(of: &RcType) -> RcType {
|
||||||
|
Rc::new(Self::Variable(Variable {
|
||||||
|
instance: RefCell::new(Some(of.clone())),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/// Creates a new [type operator](Type::Operator)
|
||||||
|
pub fn new_op(name: Sym, types: &[RcType]) -> RcType {
|
||||||
|
Rc::new(Self::Operator(Operator {
|
||||||
|
name,
|
||||||
|
types: RefCell::new(types.to_vec()),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/// Creates a new [type operator](Type::Operator) representing a lambda
|
||||||
|
pub fn new_fn(takes: &RcType, returns: &RcType) -> RcType {
|
||||||
|
Self::new_op("fn".into(), &[takes.clone(), returns.clone()])
|
||||||
|
}
|
||||||
|
/// Creates a new [type operator](Type::Operator) representing a primitive type
|
||||||
|
pub fn new_prim(name: Sym) -> RcType {
|
||||||
|
Self::new_op(name, &[])
|
||||||
|
}
|
||||||
|
/// Creates a new [type operator](Type::Operator) representing a tuple
|
||||||
|
pub fn new_tuple(members: &[RcType]) -> RcType {
|
||||||
|
Self::new_op("tuple".into(), members)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets this type variable to be an instance `of` the other
|
||||||
|
/// # Panics
|
||||||
|
/// Panics if `self` is not a type variable
|
||||||
|
pub fn set_instance(self: &RcType, of: &RcType) {
|
||||||
|
match self.as_ref() {
|
||||||
|
Type::Operator(_) => unimplemented!("Cannot set instance of a type operator"),
|
||||||
|
Type::Variable(Variable { instance }) => *instance.borrow_mut() = Some(of.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Checks whether there are any unbound type variables in this type.
|
||||||
|
/// ```rust
|
||||||
|
/// # use cl_typeck::stage::infer::*;
|
||||||
|
/// let bool = Type::new_op("bool".into(), &[]);
|
||||||
|
/// let true_v = Type::new_inst(&bool);
|
||||||
|
/// let unbound = Type::new_var();
|
||||||
|
/// let id_fun = Type::new_fn(&unbound, &unbound);
|
||||||
|
/// let truthy = Type::new_fn(&unbound, &bool);
|
||||||
|
/// assert!(!bool.is_generic()); // bool contains no unbound type variables
|
||||||
|
/// assert!(!true_v.is_generic()); // true_v is bound to `bool`
|
||||||
|
/// assert!(unbound.is_generic()); // unbound is an unbound type variable
|
||||||
|
/// assert!(id_fun.is_generic()); // id_fun is a function with unbound type variables
|
||||||
|
/// assert!(truthy.is_generic()); // truthy is a function with one unbound type variable
|
||||||
|
/// ```
|
||||||
|
pub fn is_generic(self: &RcType) -> bool {
|
||||||
|
match self.as_ref() {
|
||||||
|
Type::Variable(Variable { instance }) => match instance.borrow().as_ref() {
|
||||||
|
// base case: self is an unbound type variable (instance is none)
|
||||||
|
None => true,
|
||||||
|
// Variable is bound to a type which may be generic
|
||||||
|
Some(instance) => instance.is_generic(),
|
||||||
|
},
|
||||||
|
Type::Operator(Operator { types, .. }) => {
|
||||||
|
// Operator may have generic args
|
||||||
|
types.borrow().iter().any(Self::is_generic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Makes a deep copy of a type expression.
|
||||||
|
///
|
||||||
|
/// Bound variables are shared, unbound variables are duplicated.
|
||||||
|
pub fn deep_clone(self: &RcType) -> RcType {
|
||||||
|
// If there aren't any unbound variables, it's fine to clone the entire expression
|
||||||
|
if !self.is_generic() {
|
||||||
|
return self.clone();
|
||||||
|
}
|
||||||
|
// There are unbound type variables, so we make a new one
|
||||||
|
match self.as_ref() {
|
||||||
|
Type::Variable { .. } => Self::new_var(),
|
||||||
|
Type::Operator(Operator { name, types }) => Self::new_op(
|
||||||
|
*name,
|
||||||
|
&types
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.map(Self::deep_clone)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Returns the defining instance of `self`,
|
||||||
|
/// collapsing type instances along the way.
|
||||||
|
/// # May panic
|
||||||
|
/// Panics if this type variable's instance field is already borrowed.
|
||||||
|
/// # Examples
|
||||||
|
/// ```rust
|
||||||
|
/// # use cl_typeck::stage::infer::*;
|
||||||
|
/// let t_bool = Type::new_op("bool".into(), &[]);
|
||||||
|
/// let t_nest = Type::new_inst(&Type::new_inst(&Type::new_inst(&t_bool)));
|
||||||
|
/// let pruned = t_nest.prune();
|
||||||
|
/// assert_eq!(pruned, t_bool);
|
||||||
|
/// assert_eq!(t_nest, Type::new_inst(&t_bool));
|
||||||
|
/// ```
|
||||||
|
pub fn prune(self: &RcType) -> RcType {
|
||||||
|
if let Type::Variable(Variable { instance }) = self.as_ref() {
|
||||||
|
if let Some(old_inst) = instance.borrow_mut().as_mut() {
|
||||||
|
let new_inst = old_inst.prune(); // get defining instance
|
||||||
|
*old_inst = new_inst.clone(); // collapse
|
||||||
|
return new_inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether a type expression occurs in another type expression
|
||||||
|
///
|
||||||
|
/// # Note:
|
||||||
|
/// - Since the test uses strict equality, `self` should be pruned prior to testing.
|
||||||
|
/// - The test is *not guaranteed to terminate* for recursive types.
|
||||||
|
pub fn occurs_in(self: &RcType, other: &RcType) -> bool {
|
||||||
|
if self == other {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
match other.as_ref() {
|
||||||
|
Type::Variable(Variable { instance }) => match instance.borrow().as_ref() {
|
||||||
|
Some(t) => self.occurs_in(t),
|
||||||
|
None => false,
|
||||||
|
},
|
||||||
|
Type::Operator(Operator { types, .. }) => {
|
||||||
|
// Note: this might panic.
|
||||||
|
// Think about whether it panics for only recursive types?
|
||||||
|
types.borrow().iter().any(|other| self.occurs_in(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unifies two type expressions, propagating changes via interior mutability
|
||||||
|
pub fn unify(self: &RcType, other: &RcType) -> Result<(), InferenceError> {
|
||||||
|
let (a, b) = (self.prune(), other.prune()); // trim the hedges
|
||||||
|
match (a.as_ref(), b.as_ref()) {
|
||||||
|
(Type::Variable { .. }, _) if !a.occurs_in(&b) => a.set_instance(&b),
|
||||||
|
(Type::Variable { .. }, _) => Err(InferenceError::Recursive(a, b))?,
|
||||||
|
(Type::Operator { .. }, Type::Variable { .. }) => b.unify(&a)?,
|
||||||
|
(
|
||||||
|
Type::Operator(Operator { name: a_name, types: a_types }),
|
||||||
|
Type::Operator(Operator { name: b_name, types: b_types }),
|
||||||
|
) => {
|
||||||
|
let (a_types, b_types) = (a_types.borrow(), b_types.borrow());
|
||||||
|
if a_name != b_name || a_types.len() != b_types.len() {
|
||||||
|
Err(InferenceError::Mismatch(a.clone(), b.clone()))?
|
||||||
|
}
|
||||||
|
for (a, b) in a_types.iter().zip(b_types.iter()) {
|
||||||
|
a.unify(b)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Type {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Type::Variable(Variable { instance }) => match instance.borrow().as_ref() {
|
||||||
|
Some(instance) => write!(f, "{instance}"),
|
||||||
|
None => write!(f, "_"),
|
||||||
|
},
|
||||||
|
Type::Operator(Operator { name, types }) => {
|
||||||
|
write!(f, "({name}")?;
|
||||||
|
for ty in types.borrow().iter() {
|
||||||
|
write!(f, " {ty}")?;
|
||||||
|
}
|
||||||
|
f.write_str(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An error produced during type inference
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum InferenceError {
|
||||||
|
Mismatch(RcType, RcType),
|
||||||
|
Recursive(RcType, RcType),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InferenceError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
InferenceError::Mismatch(a, b) => write!(f, "Type mismatch: {a:?} != {b:?}"),
|
||||||
|
InferenceError::Recursive(_, _) => write!(f, "Recursive type!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,528 +0,0 @@
|
|||||||
use super::error::InferenceError;
|
|
||||||
use crate::{
|
|
||||||
entry::Entry,
|
|
||||||
handle::Handle,
|
|
||||||
stage::infer::inference::Inference,
|
|
||||||
table::{NodeKind, Table},
|
|
||||||
type_expression::TypeExpression,
|
|
||||||
type_kind::{Adt, Primitive, TypeKind},
|
|
||||||
};
|
|
||||||
use cl_ast::Sym;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Types in Conlang:
|
|
||||||
- Never type: !
|
|
||||||
- type !
|
|
||||||
- for<A> ! -> A
|
|
||||||
- Primitive types: bool, i32, (), ...
|
|
||||||
- type bool; ...
|
|
||||||
- Reference types: &T, *T
|
|
||||||
- for<T> type ref<T>; for<T> type ptr<T>
|
|
||||||
- Slice type: [T]
|
|
||||||
- for<T> type slice<T>
|
|
||||||
- Array type: [T;usize]
|
|
||||||
- for<T> type array<T, instanceof<usize>>
|
|
||||||
- Tuple type: (T, ...Z)
|
|
||||||
- for<T, ..> type tuple<T, ..> // on a per-case basis!
|
|
||||||
- Funct type: fn Tuple -> R
|
|
||||||
- for<T, R> type T -> R // on a per-case basis!
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub struct InferenceEngine<'table, 'a> {
|
|
||||||
pub(super) table: &'table mut Table<'a>,
|
|
||||||
/// The current working node
|
|
||||||
pub(crate) at: Handle,
|
|
||||||
/// The current breakset
|
|
||||||
pub(crate) bset: Handle,
|
|
||||||
/// The current returnset
|
|
||||||
pub(crate) rset: Handle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|
||||||
/// Infers the type of an object by deferring to [`Inference::infer()`]
|
|
||||||
pub fn infer(&mut self, inferrable: &'a impl Inference<'a>) -> Result<Handle, InferenceError> {
|
|
||||||
inferrable.infer(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a new [`InferenceEngine`], scoped around a [`Handle`] in a [`Table`].
|
|
||||||
pub fn new(table: &'table mut Table<'a>, at: Handle) -> Self {
|
|
||||||
let never = table.anon_type(TypeKind::Never);
|
|
||||||
Self { at, table, bset: never, rset: never }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs an [`InferenceEngine`] that borrows the same table as `self`,
|
|
||||||
/// but with a shortened lifetime.
|
|
||||||
pub fn scoped(&mut self) -> InferenceEngine<'_, 'a> {
|
|
||||||
InferenceEngine { at: self.at, table: self.table, bset: self.bset, rset: self.rset }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn infer_all(&mut self) -> Vec<(Handle, InferenceError)> {
|
|
||||||
let iter = self.table.handle_iter();
|
|
||||||
let mut res = Vec::new();
|
|
||||||
for handle in iter {
|
|
||||||
let mut eng = self.at(handle);
|
|
||||||
// TODO: use sources instead of bodies, and infer the type globally
|
|
||||||
let Some(body) = eng.table.body(handle) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
eprintln!("Evaluating body {body}");
|
|
||||||
match body.infer(&mut eng) {
|
|
||||||
Ok(ty) => println!("=> {}", eng.table.entry(ty)),
|
|
||||||
Err(e) => {
|
|
||||||
match &e {
|
|
||||||
&InferenceError::Mismatch(a, b) => {
|
|
||||||
eprintln!(
|
|
||||||
"=> Mismatched types: {}, {}",
|
|
||||||
eng.table.entry(a),
|
|
||||||
eng.table.entry(b)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
&InferenceError::Recursive(a, b) => {
|
|
||||||
eprintln!(
|
|
||||||
"=> Recursive types: {}, {}",
|
|
||||||
eng.table.entry(a),
|
|
||||||
eng.table.entry(b)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
e => eprintln!("=> {e}"),
|
|
||||||
}
|
|
||||||
res.push((handle, e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a new InferenceEngine with the
|
|
||||||
pub fn at(&mut self, at: Handle) -> InferenceEngine<'_, 'a> {
|
|
||||||
InferenceEngine { at, ..self.scoped() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_bset(&mut self) -> InferenceEngine<'_, 'a> {
|
|
||||||
InferenceEngine { bset: self.new_var(), ..self.scoped() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_rset(&mut self) -> InferenceEngine<'_, 'a> {
|
|
||||||
InferenceEngine { rset: self.new_var(), ..self.scoped() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs an [Entry] out of a [Handle], for ease of use
|
|
||||||
pub fn entry(&self, of: Handle) -> Entry<'_, 'a> {
|
|
||||||
self.table.entry(of)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deprecated = "Use dedicated methods instead."]
|
|
||||||
pub fn from_type_kind(&mut self, kind: TypeKind) -> Handle {
|
|
||||||
// TODO: preserve type heirarchy (for, i.e., reference types)
|
|
||||||
self.table.anon_type(kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn by_name<Out, N: TypeExpression<Out>>(
|
|
||||||
&mut self,
|
|
||||||
name: &N,
|
|
||||||
) -> Result<Out, crate::type_expression::Error> {
|
|
||||||
name.evaluate(self.table, self.at)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new unbound [type variable](Handle)
|
|
||||||
pub fn new_var(&mut self) -> Handle {
|
|
||||||
self.table.type_variable()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a variable that is a new instance of another [Type](Handle)
|
|
||||||
pub fn new_inst(&mut self, of: Handle) -> Handle {
|
|
||||||
self.table.anon_type(TypeKind::Instance(of))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the defining usage of a type without collapsing intermediates
|
|
||||||
pub fn def_usage(&self, to: Handle) -> Handle {
|
|
||||||
match self.table.entry(to).ty() {
|
|
||||||
Some(TypeKind::Instance(id)) => self.def_usage(*id),
|
|
||||||
_ => to,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_fn(&self, at: Handle, name: Sym) -> Option<(Handle, Handle)> {
|
|
||||||
use cl_ast::PathPart;
|
|
||||||
if let Some(&TypeKind::FnSig { args, rety }) = self
|
|
||||||
.entry(at)
|
|
||||||
.nav(&[PathPart::Ident(name)])
|
|
||||||
.as_ref()
|
|
||||||
.and_then(Entry::ty)
|
|
||||||
{
|
|
||||||
Some((args, rety))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new type variable representing a tuple
|
|
||||||
pub fn new_tuple(&mut self, tys: Vec<Handle>) -> Handle {
|
|
||||||
self.table.anon_type(TypeKind::Tuple(tys))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new type variable representing an array
|
|
||||||
pub fn new_array(&mut self, ty: Handle, size: usize) -> Handle {
|
|
||||||
self.table.anon_type(TypeKind::Array(ty, size))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new type variable representing a slice of contiguous memory
|
|
||||||
pub fn new_slice(&mut self, ty: Handle) -> Handle {
|
|
||||||
self.table.anon_type(TypeKind::Slice(ty))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new reference to a type
|
|
||||||
pub fn new_ref(&mut self, to: Handle) -> Handle {
|
|
||||||
self.table.anon_type(TypeKind::Ref(to))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// All primitives must be predefined in the standard library.
|
|
||||||
pub fn primitive(&self, name: Sym) -> Option<Handle> {
|
|
||||||
// TODO: keep a map of primitives in the table root
|
|
||||||
self.table.get_by_sym(self.table.root(), &name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn never(&mut self) -> Handle {
|
|
||||||
self.table.anon_type(TypeKind::Never)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn empty(&mut self) -> Handle {
|
|
||||||
self.table.anon_type(TypeKind::Empty)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bool(&self) -> Handle {
|
|
||||||
self.primitive("bool".into())
|
|
||||||
.expect("There should be a type named bool.")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn char(&self) -> Handle {
|
|
||||||
self.primitive("char".into())
|
|
||||||
.expect("There should be a type named char.")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn str(&self) -> Handle {
|
|
||||||
self.primitive("str".into())
|
|
||||||
.expect("There should be a type named str.")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn u32(&self) -> Handle {
|
|
||||||
self.primitive("u32".into())
|
|
||||||
.expect("There should be a type named u32.")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn usize(&self) -> Handle {
|
|
||||||
self.primitive("usize".into())
|
|
||||||
.expect("There should be a type named usize.")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new inferred-integer literal
|
|
||||||
pub fn integer_literal(&mut self) -> Handle {
|
|
||||||
let h = self.table.new_entry(self.at, NodeKind::Local);
|
|
||||||
self.table
|
|
||||||
.set_ty(h, TypeKind::Primitive(Primitive::Integer));
|
|
||||||
h
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new inferred-float literal
|
|
||||||
pub fn float_literal(&mut self) -> Handle {
|
|
||||||
let h = self.table.new_entry(self.at, NodeKind::Local);
|
|
||||||
self.table.set_ty(h, TypeKind::Primitive(Primitive::Float));
|
|
||||||
h
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enters a new scope
|
|
||||||
pub fn local_scope(&mut self) {
|
|
||||||
let scope = self.table.new_entry(self.at, NodeKind::Local);
|
|
||||||
self.at = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new locally-scoped InferenceEngine.
|
|
||||||
pub fn block_scope(&mut self) -> InferenceEngine<'_, 'a> {
|
|
||||||
let scope = self.table.new_entry(self.at, NodeKind::Local);
|
|
||||||
self.at(scope)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets this type variable `to` be an instance `of` the other
|
|
||||||
/// # Panics
|
|
||||||
/// Panics if `to` is not a type variable
|
|
||||||
pub fn set_instance(&mut self, to: Handle, of: Handle) {
|
|
||||||
let mut e = self.table.entry_mut(to);
|
|
||||||
match e.as_ref().ty() {
|
|
||||||
Some(TypeKind::Inferred) => {
|
|
||||||
if let Some(ty) = self.table.ty(of) {
|
|
||||||
self.table.set_ty(to, ty.clone());
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Some(TypeKind::Variable)
|
|
||||||
| Some(TypeKind::Primitive(Primitive::Float | Primitive::Integer)) => {
|
|
||||||
e.set_ty(TypeKind::Instance(of))
|
|
||||||
}
|
|
||||||
other => todo!("Cannot set {} to instance of: {other:?}", e.as_ref()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether there are any unbound type variables in this type
|
|
||||||
pub fn is_generic(&self, ty: Handle) -> bool {
|
|
||||||
let entry = self.table.entry(ty);
|
|
||||||
let Some(ty) = entry.ty() else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
match ty {
|
|
||||||
TypeKind::Inferred => false,
|
|
||||||
TypeKind::Variable => true,
|
|
||||||
&TypeKind::Array(h, _) => self.is_generic(h),
|
|
||||||
&TypeKind::Instance(h) => self.is_generic(h),
|
|
||||||
TypeKind::Primitive(_) => false,
|
|
||||||
TypeKind::Adt(Adt::Enum(tys)) => tys.iter().any(|(_, ty)| self.is_generic(*ty)),
|
|
||||||
TypeKind::Adt(Adt::Struct(tys)) => tys.iter().any(|&(_, _, ty)| self.is_generic(ty)),
|
|
||||||
TypeKind::Adt(Adt::TupleStruct(tys)) => tys.iter().any(|&(_, ty)| self.is_generic(ty)),
|
|
||||||
TypeKind::Adt(Adt::UnitStruct) => false,
|
|
||||||
TypeKind::Adt(Adt::Union(tys)) => tys.iter().any(|&(_, ty)| self.is_generic(ty)),
|
|
||||||
&TypeKind::Ref(h) => self.is_generic(h),
|
|
||||||
&TypeKind::Slice(h) => self.is_generic(h),
|
|
||||||
TypeKind::Tuple(handles) => handles.iter().any(|&ty| self.is_generic(ty)),
|
|
||||||
&TypeKind::FnSig { args, rety } => self.is_generic(args) || self.is_generic(rety),
|
|
||||||
TypeKind::Empty | TypeKind::Never | TypeKind::Module => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes a deep copy of a type expression.
|
|
||||||
///
|
|
||||||
/// Bound variables are shared, unbound variables are duplicated.
|
|
||||||
pub fn deep_clone(&mut self, ty: Handle) -> Handle {
|
|
||||||
if !self.is_generic(ty) {
|
|
||||||
return ty;
|
|
||||||
};
|
|
||||||
let entry = self.table.entry(ty);
|
|
||||||
let Some(ty) = entry.ty().cloned() else {
|
|
||||||
return ty;
|
|
||||||
};
|
|
||||||
match ty {
|
|
||||||
TypeKind::Variable => self.new_var(),
|
|
||||||
TypeKind::Array(h, s) => {
|
|
||||||
let ty = self.deep_clone(h);
|
|
||||||
self.table.anon_type(TypeKind::Array(ty, s))
|
|
||||||
}
|
|
||||||
TypeKind::Instance(h) => {
|
|
||||||
let ty = self.deep_clone(h);
|
|
||||||
self.table.anon_type(TypeKind::Instance(ty))
|
|
||||||
}
|
|
||||||
TypeKind::Adt(Adt::Enum(tys)) => {
|
|
||||||
let tys = tys
|
|
||||||
.into_iter()
|
|
||||||
.map(|(name, ty)| (name, self.deep_clone(ty)))
|
|
||||||
.collect();
|
|
||||||
self.table.anon_type(TypeKind::Adt(Adt::Enum(tys)))
|
|
||||||
}
|
|
||||||
TypeKind::Adt(Adt::Struct(tys)) => {
|
|
||||||
let tys = tys
|
|
||||||
.into_iter()
|
|
||||||
.map(|(n, v, ty)| (n, v, self.deep_clone(ty)))
|
|
||||||
.collect();
|
|
||||||
self.table.anon_type(TypeKind::Adt(Adt::Struct(tys)))
|
|
||||||
}
|
|
||||||
TypeKind::Adt(Adt::TupleStruct(tys)) => {
|
|
||||||
let tys = tys
|
|
||||||
.into_iter()
|
|
||||||
.map(|(v, ty)| (v, self.deep_clone(ty)))
|
|
||||||
.collect();
|
|
||||||
self.table.anon_type(TypeKind::Adt(Adt::TupleStruct(tys)))
|
|
||||||
}
|
|
||||||
TypeKind::Adt(Adt::Union(tys)) => {
|
|
||||||
let tys = tys
|
|
||||||
.into_iter()
|
|
||||||
.map(|(n, ty)| (n, self.deep_clone(ty)))
|
|
||||||
.collect();
|
|
||||||
self.table.anon_type(TypeKind::Adt(Adt::Union(tys)))
|
|
||||||
}
|
|
||||||
TypeKind::Ref(h) => {
|
|
||||||
let ty = self.deep_clone(h);
|
|
||||||
self.table.anon_type(TypeKind::Ref(ty))
|
|
||||||
}
|
|
||||||
TypeKind::Slice(h) => {
|
|
||||||
let ty = self.deep_clone(h);
|
|
||||||
self.table.anon_type(TypeKind::Slice(ty))
|
|
||||||
}
|
|
||||||
TypeKind::Tuple(tys) => {
|
|
||||||
let tys = tys.into_iter().map(|ty| self.deep_clone(ty)).collect();
|
|
||||||
self.table.anon_type(TypeKind::Tuple(tys))
|
|
||||||
}
|
|
||||||
TypeKind::FnSig { args, rety } => {
|
|
||||||
let args = self.deep_clone(args);
|
|
||||||
let rety = self.deep_clone(rety);
|
|
||||||
self.table.anon_type(TypeKind::FnSig { args, rety })
|
|
||||||
}
|
|
||||||
_ => self.table.anon_type(ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the defining instance of `self`,
|
|
||||||
/// collapsing type instances along the way.
|
|
||||||
pub fn prune(&mut self, ty: Handle) -> Handle {
|
|
||||||
if let Some(TypeKind::Instance(new_ty)) = self.table.ty(ty) {
|
|
||||||
let new_ty = self.prune(*new_ty);
|
|
||||||
self.table.set_ty(ty, TypeKind::Instance(new_ty));
|
|
||||||
new_ty
|
|
||||||
} else {
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether a type occurs in another type
|
|
||||||
///
|
|
||||||
/// # Note:
|
|
||||||
/// - Since the test uses strict equality, `self` should be pruned prior to testing.
|
|
||||||
/// - The test is *not guaranteed to terminate* for recursive types.
|
|
||||||
pub fn occurs_in(&self, this: Handle, other: Handle) -> bool {
|
|
||||||
if this == other {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
let Some(ty) = self.table.ty(other) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
match ty {
|
|
||||||
TypeKind::Instance(other) => self.occurs_in(this, *other),
|
|
||||||
TypeKind::Adt(Adt::Enum(items)) => {
|
|
||||||
items.iter().any(|(_, other)| self.occurs_in(this, *other))
|
|
||||||
}
|
|
||||||
TypeKind::Adt(Adt::Struct(items)) => items
|
|
||||||
.iter()
|
|
||||||
.any(|(_, _, other)| self.occurs_in(this, *other)),
|
|
||||||
TypeKind::Adt(Adt::TupleStruct(items)) => {
|
|
||||||
items.iter().any(|(_, other)| self.occurs_in(this, *other))
|
|
||||||
}
|
|
||||||
TypeKind::Adt(Adt::Union(items)) => {
|
|
||||||
items.iter().any(|(_, other)| self.occurs_in(this, *other))
|
|
||||||
}
|
|
||||||
TypeKind::Ref(other) => self.occurs_in(this, *other),
|
|
||||||
TypeKind::Slice(other) => self.occurs_in(this, *other),
|
|
||||||
TypeKind::Array(other, _) => self.occurs_in(this, *other),
|
|
||||||
TypeKind::Tuple(handles) => handles.iter().any(|&other| self.occurs_in(this, other)),
|
|
||||||
TypeKind::FnSig { args, rety } => {
|
|
||||||
self.occurs_in(this, *args) || self.occurs_in(this, *rety)
|
|
||||||
}
|
|
||||||
TypeKind::Inferred
|
|
||||||
| TypeKind::Variable
|
|
||||||
| TypeKind::Adt(Adt::UnitStruct)
|
|
||||||
| TypeKind::Primitive(_)
|
|
||||||
| TypeKind::Empty
|
|
||||||
| TypeKind::Never
|
|
||||||
| TypeKind::Module => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unifies two types
|
|
||||||
pub fn unify(&mut self, this: Handle, other: Handle) -> Result<(), InferenceError> {
|
|
||||||
let (ah, bh) = (self.prune(this), self.prune(other));
|
|
||||||
let (a, b) = (self.table.entry(ah), self.table.entry(bh));
|
|
||||||
let (Some(a), Some(b)) = (a.ty(), b.ty()) else {
|
|
||||||
return Err(InferenceError::Mismatch(ah, bh));
|
|
||||||
};
|
|
||||||
|
|
||||||
match (a, b) {
|
|
||||||
(TypeKind::Inferred, _) => {
|
|
||||||
self.set_instance(ah, bh);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(_, TypeKind::Inferred) => self.unify(bh, ah),
|
|
||||||
|
|
||||||
(TypeKind::Variable, _) => {
|
|
||||||
self.set_instance(ah, bh);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Instance(a), TypeKind::Instance(b)) if !self.occurs_in(*a, *b) => {
|
|
||||||
self.set_instance(*a, *b);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Instance(_), _) => Err(InferenceError::Recursive(ah, bh)),
|
|
||||||
|
|
||||||
(TypeKind::Primitive(Primitive::Float), TypeKind::Primitive(Primitive::Integer))
|
|
||||||
| (TypeKind::Primitive(Primitive::Integer), TypeKind::Primitive(Primitive::Float)) => {
|
|
||||||
Err(InferenceError::Mismatch(ah, bh))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primitives have their own set of vars which only unify with primitives.
|
|
||||||
(TypeKind::Primitive(Primitive::Integer), TypeKind::Primitive(i)) if i.is_integer() => {
|
|
||||||
self.set_instance(ah, bh);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Primitive(Primitive::Float), TypeKind::Primitive(f)) if f.is_float() => {
|
|
||||||
self.set_instance(ah, bh);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
(_, TypeKind::Variable)
|
|
||||||
| (_, TypeKind::Instance(_))
|
|
||||||
| (TypeKind::Primitive(_), TypeKind::Primitive(Primitive::Integer))
|
|
||||||
| (TypeKind::Primitive(_), TypeKind::Primitive(Primitive::Float)) => self.unify(bh, ah),
|
|
||||||
(TypeKind::Adt(Adt::Enum(ia)), TypeKind::Adt(Adt::Enum(ib)))
|
|
||||||
if ia.len() == ib.len() =>
|
|
||||||
{
|
|
||||||
for ((na, a), (nb, b)) in ia.clone().into_iter().zip(ib.clone().into_iter()) {
|
|
||||||
if na != nb {
|
|
||||||
return Err(InferenceError::Mismatch(ah, bh));
|
|
||||||
}
|
|
||||||
self.unify(a, b)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Adt(Adt::Struct(ia)), TypeKind::Adt(Adt::Struct(ib)))
|
|
||||||
if ia.len() == ib.len() =>
|
|
||||||
{
|
|
||||||
for ((na, va, a), (nb, vb, b)) in ia.clone().into_iter().zip(ib.clone().into_iter())
|
|
||||||
{
|
|
||||||
if na != nb || va != vb {
|
|
||||||
return Err(InferenceError::Mismatch(ah, bh));
|
|
||||||
}
|
|
||||||
self.unify(a, b)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Adt(Adt::TupleStruct(ia)), TypeKind::Adt(Adt::TupleStruct(ib)))
|
|
||||||
if ia.len() == ib.len() =>
|
|
||||||
{
|
|
||||||
for ((va, a), (vb, b)) in ia.clone().into_iter().zip(ib.clone().into_iter()) {
|
|
||||||
if va != vb {
|
|
||||||
return Err(InferenceError::Mismatch(ah, bh));
|
|
||||||
}
|
|
||||||
self.unify(a, b)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Adt(Adt::Union(ia)), TypeKind::Adt(Adt::Union(ib)))
|
|
||||||
if ia.len() == ib.len() =>
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
(TypeKind::Ref(a), TypeKind::Ref(b)) => self.unify(*a, *b),
|
|
||||||
(TypeKind::Slice(a), TypeKind::Slice(b)) => self.unify(*a, *b),
|
|
||||||
// Slice unifies with array
|
|
||||||
(TypeKind::Array(a, _), TypeKind::Slice(b)) => self.unify(*a, *b),
|
|
||||||
(TypeKind::Slice(_), TypeKind::Array(_, _)) => self.unify(bh, ah),
|
|
||||||
(TypeKind::Array(a, sa), TypeKind::Array(b, sb)) if sa == sb => self.unify(*a, *b),
|
|
||||||
(TypeKind::Tuple(a), TypeKind::Tuple(b)) => {
|
|
||||||
if a.len() != b.len() {
|
|
||||||
return Err(InferenceError::Mismatch(ah, bh));
|
|
||||||
}
|
|
||||||
let (a, b) = (a.clone(), b.clone());
|
|
||||||
for (a, b) in a.iter().zip(b.iter()) {
|
|
||||||
self.unify(*a, *b)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(&TypeKind::FnSig { args: a1, rety: r1 }, &TypeKind::FnSig { args: a2, rety: r2 }) => {
|
|
||||||
self.unify(a1, a2)?;
|
|
||||||
self.unify(r1, r2)
|
|
||||||
}
|
|
||||||
(TypeKind::Empty, TypeKind::Tuple(t)) | (TypeKind::Tuple(t), TypeKind::Empty)
|
|
||||||
if t.is_empty() =>
|
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Never, _) | (_, TypeKind::Never) => Ok(()),
|
|
||||||
(a, b) if a == b => Ok(()),
|
|
||||||
_ => Err(InferenceError::Mismatch(ah, bh)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
use cl_ast::Path;
|
|
||||||
|
|
||||||
use crate::handle::Handle;
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
/// An error produced during type inference
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub enum InferenceError {
|
|
||||||
AnnotationEval(crate::type_expression::Error),
|
|
||||||
FieldCount(Handle, usize, usize),
|
|
||||||
NotFound(Path),
|
|
||||||
Mismatch(Handle, Handle),
|
|
||||||
Recursive(Handle, Handle),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for InferenceError {}
|
|
||||||
#[rustfmt::skip]
|
|
||||||
impl fmt::Display for InferenceError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
InferenceError::AnnotationEval(error) => write!(f, "{error}"),
|
|
||||||
InferenceError::FieldCount(name, want, got) => {
|
|
||||||
write!(f,
|
|
||||||
"Struct {name} {} fields! Expected {want}, got {got}",
|
|
||||||
if want < got { "has too many" } else { "is missing" }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
InferenceError::NotFound(p) => write!(f, "Path not visible in scope: {p}"),
|
|
||||||
InferenceError::Mismatch(a, b) => write!(f, "Type mismatch: {a:?} != {b:?}"),
|
|
||||||
InferenceError::Recursive(_, _) => write!(f, "Recursive type!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,698 +0,0 @@
|
|||||||
//! The [Inference] trait is the heart of cl-typeck's type inference.
|
|
||||||
//!
|
|
||||||
//! Each syntax structure must describe how to unify its types.
|
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use super::{engine::InferenceEngine, error::InferenceError};
|
|
||||||
use crate::{
|
|
||||||
handle::Handle,
|
|
||||||
table::NodeKind,
|
|
||||||
type_expression::TypeExpression,
|
|
||||||
type_kind::{Adt, TypeKind},
|
|
||||||
};
|
|
||||||
use cl_ast::*;
|
|
||||||
|
|
||||||
// TODO: "Infer" the types of Items
|
|
||||||
|
|
||||||
type IfResult = Result<Handle, InferenceError>;
|
|
||||||
|
|
||||||
pub trait Inference<'a> {
|
|
||||||
/// Performs type inference
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for cl_ast::Expr {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
self.kind.infer(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for cl_ast::ExprKind {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
match self {
|
|
||||||
ExprKind::Empty => Ok(e.empty()),
|
|
||||||
ExprKind::Closure(_) => todo!("Infer the type of a closure"),
|
|
||||||
ExprKind::Tuple(tuple) => tuple.infer(e),
|
|
||||||
ExprKind::Structor(structor) => structor.infer(e),
|
|
||||||
ExprKind::Array(array) => array.infer(e),
|
|
||||||
ExprKind::ArrayRep(array_rep) => array_rep.infer(e),
|
|
||||||
ExprKind::AddrOf(addr_of) => addr_of.infer(e),
|
|
||||||
ExprKind::Quote(quote) => quote.infer(e),
|
|
||||||
ExprKind::Literal(literal) => literal.infer(e),
|
|
||||||
|
|
||||||
ExprKind::Group(group) => group.infer(e),
|
|
||||||
ExprKind::Block(block) => block.infer(e),
|
|
||||||
|
|
||||||
ExprKind::Assign(assign) => assign.infer(e),
|
|
||||||
ExprKind::Modify(modify) => modify.infer(e),
|
|
||||||
ExprKind::Binary(binary) => binary.infer(e),
|
|
||||||
ExprKind::Unary(unary) => unary.infer(e),
|
|
||||||
ExprKind::Member(member) => member.infer(e),
|
|
||||||
ExprKind::Index(index) => index.infer(e),
|
|
||||||
ExprKind::Path(path) => path.infer(e),
|
|
||||||
ExprKind::Cast(cast) => cast.infer(e),
|
|
||||||
|
|
||||||
ExprKind::Let(l) => l.infer(e),
|
|
||||||
ExprKind::Match(m) => m.infer(e),
|
|
||||||
ExprKind::While(w) => w.infer(e),
|
|
||||||
ExprKind::If(i) => i.infer(e),
|
|
||||||
ExprKind::For(f) => f.infer(e),
|
|
||||||
ExprKind::Break(b) => b.infer(e),
|
|
||||||
ExprKind::Return(r) => r.infer(e),
|
|
||||||
ExprKind::Continue => Ok(e.never()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Tuple {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Tuple { exprs } = self;
|
|
||||||
exprs
|
|
||||||
.iter()
|
|
||||||
// Infer each member
|
|
||||||
.map(|expr| expr.infer(e))
|
|
||||||
// Construct tuple
|
|
||||||
.collect::<Result<Vec<_>, InferenceError>>()
|
|
||||||
// Return tuple
|
|
||||||
.map(|tys| e.new_tuple(tys))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Structor {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Structor { to, init } = self;
|
|
||||||
// Evaluate the path in the current context
|
|
||||||
let to = to.infer(e)?;
|
|
||||||
match e.entry(to).ty() {
|
|
||||||
// Typecheck the fielders against the fields
|
|
||||||
Some(TypeKind::Adt(Adt::Struct(fields))) => {
|
|
||||||
if init.len() != fields.len() {
|
|
||||||
return Err(InferenceError::FieldCount(to, fields.len(), init.len()));
|
|
||||||
}
|
|
||||||
let fields = fields.clone(); // todo: fix this somehow.
|
|
||||||
let mut field_inits: std::collections::HashMap<_, _> = init
|
|
||||||
.iter()
|
|
||||||
.map(|Fielder { name, init }| (name, init))
|
|
||||||
.collect();
|
|
||||||
// Unify fields with fielders
|
|
||||||
for (name, _vis, ty) in fields {
|
|
||||||
match field_inits.remove(&name) {
|
|
||||||
Some(Some(field)) => {
|
|
||||||
let init_ty = field.infer(e)?;
|
|
||||||
e.unify(init_ty, ty)?;
|
|
||||||
}
|
|
||||||
Some(None) => {
|
|
||||||
// Get name in scope
|
|
||||||
let init_ty = e
|
|
||||||
.table
|
|
||||||
.get_by_sym(e.at, &name)
|
|
||||||
.ok_or_else(|| InferenceError::NotFound(Path::from(name)))?;
|
|
||||||
e.unify(init_ty, ty)?;
|
|
||||||
}
|
|
||||||
None => Err(InferenceError::NotFound(Path::from(name)))?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(to)
|
|
||||||
}
|
|
||||||
_ => Err(InferenceError::NotFound(self.to.clone())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Array {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Array { values } = self;
|
|
||||||
let out = e.new_var();
|
|
||||||
for value in values {
|
|
||||||
let ty = value.infer(e)?;
|
|
||||||
e.unify(out, ty)?;
|
|
||||||
}
|
|
||||||
Ok(e.new_array(out, values.len()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for ArrayRep {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let ArrayRep { value, repeat } = self;
|
|
||||||
let ty = value.infer(e)?;
|
|
||||||
Ok(e.new_array(ty, *repeat))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for AddrOf {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let AddrOf { mutable: _, expr } = self;
|
|
||||||
// TODO: mut ref
|
|
||||||
let ty = expr.infer(e)?;
|
|
||||||
Ok(e.new_ref(ty))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Quote {
|
|
||||||
fn infer(&'a self, _e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
todo!("Quote: {self}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Literal {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let ty = match self {
|
|
||||||
Literal::Bool(_) => e.bool(),
|
|
||||||
Literal::Char(_) => e.char(),
|
|
||||||
Literal::Int(_) => e.integer_literal(),
|
|
||||||
Literal::Float(_) => e.float_literal(),
|
|
||||||
Literal::String(_) => {
|
|
||||||
let str_ty = e.str();
|
|
||||||
e.new_ref(str_ty)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(e.new_inst(ty))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Group {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Group { expr } = self;
|
|
||||||
expr.infer(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Block {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Block { stmts } = self;
|
|
||||||
let mut e = e.block_scope();
|
|
||||||
let empty = e.empty();
|
|
||||||
if let [stmts @ .., ret] = stmts.as_slice() {
|
|
||||||
for stmt in stmts {
|
|
||||||
match (&stmt.kind, &stmt.semi) {
|
|
||||||
(StmtKind::Expr(expr), Semi::Terminated) => {
|
|
||||||
expr.infer(&mut e)?;
|
|
||||||
}
|
|
||||||
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
|
||||||
let ty = expr.infer(&mut e)?;
|
|
||||||
e.unify(ty, empty)?;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match (&ret.kind, &ret.semi) {
|
|
||||||
(StmtKind::Expr(expr), Semi::Terminated) => {
|
|
||||||
expr.infer(&mut e)?;
|
|
||||||
}
|
|
||||||
(StmtKind::Expr(expr), Semi::Unterminated) => {
|
|
||||||
return expr.infer(&mut e);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(empty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Assign {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Assign { parts } = self;
|
|
||||||
let (head, tail) = parts.as_ref();
|
|
||||||
// Infer the tail expression
|
|
||||||
let tail = tail.infer(e)?;
|
|
||||||
// Infer the head expression
|
|
||||||
let head = head.infer(e)?;
|
|
||||||
// Unify head and tail
|
|
||||||
e.unify(head, tail)?;
|
|
||||||
// Return Empty
|
|
||||||
Ok(e.empty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Modify {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Modify { kind: _, parts } = self;
|
|
||||||
let (head, tail) = parts.as_ref();
|
|
||||||
// Infer the tail expression
|
|
||||||
let tail = tail.infer(e)?;
|
|
||||||
// Infer the head expression
|
|
||||||
let head = head.infer(e)?;
|
|
||||||
// TODO: Search within the head type for `(op)_assign`
|
|
||||||
e.unify(head, tail)?;
|
|
||||||
// TODO: Typecheck `op_assign(&mut head, tail)`
|
|
||||||
Ok(e.empty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Binary {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
use BinaryKind as Bk;
|
|
||||||
let Binary { kind, parts } = self;
|
|
||||||
let (head, tail) = parts.as_ref();
|
|
||||||
// Infer the tail expression
|
|
||||||
let tail = tail.infer(e)?;
|
|
||||||
// Infer the head expression
|
|
||||||
let head = head.infer(e)?;
|
|
||||||
let head = e.prune(head);
|
|
||||||
// TODO: Search within the head type for `(op)`
|
|
||||||
match kind {
|
|
||||||
BinaryKind::Call => match e.entry(head).ty() {
|
|
||||||
Some(TypeKind::Adt(Adt::TupleStruct(types))) => {
|
|
||||||
let Some(TypeKind::Tuple(values)) = e.entry(tail).ty() else {
|
|
||||||
Err(InferenceError::Mismatch(head, tail))?
|
|
||||||
};
|
|
||||||
if types.len() != values.len() {
|
|
||||||
Err(InferenceError::FieldCount(head, types.len(), values.len()))?
|
|
||||||
}
|
|
||||||
let pairs = types
|
|
||||||
.iter()
|
|
||||||
.zip(values.iter())
|
|
||||||
.map(|(&(_vis, ty), &value)| (ty, value))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for (ty, value) in pairs {
|
|
||||||
e.unify(ty, value)?;
|
|
||||||
}
|
|
||||||
Ok(head)
|
|
||||||
}
|
|
||||||
Some(&TypeKind::FnSig { args, rety }) => {
|
|
||||||
e.unify(tail, args)?;
|
|
||||||
Ok(rety)
|
|
||||||
}
|
|
||||||
_ => Err(InferenceError::Mismatch(head, tail))?,
|
|
||||||
},
|
|
||||||
Bk::Lt | Bk::LtEq | Bk::Equal | Bk::NotEq | Bk::GtEq | Bk::Gt => {
|
|
||||||
e.unify(head, tail)?;
|
|
||||||
Ok(e.bool())
|
|
||||||
}
|
|
||||||
Bk::LogAnd | Bk::LogOr | Bk::LogXor => {
|
|
||||||
let bool = e.bool();
|
|
||||||
e.unify(head, bool)?;
|
|
||||||
e.unify(tail, bool)?;
|
|
||||||
Ok(bool)
|
|
||||||
}
|
|
||||||
Bk::RangeExc => todo!("Ranges in the type checker"),
|
|
||||||
Bk::RangeInc => todo!("Ranges in the type checker"),
|
|
||||||
Bk::Shl | Bk::Shr => {
|
|
||||||
let shift_amount = e.u32();
|
|
||||||
e.unify(tail, shift_amount)?;
|
|
||||||
Ok(head)
|
|
||||||
}
|
|
||||||
Bk::BitAnd
|
|
||||||
| Bk::BitOr
|
|
||||||
| Bk::BitXor
|
|
||||||
| Bk::Add
|
|
||||||
| Bk::Sub
|
|
||||||
| Bk::Mul
|
|
||||||
| Bk::Div
|
|
||||||
| Bk::Rem => {
|
|
||||||
// Typecheck op(head, tail)
|
|
||||||
e.unify(head, tail)?;
|
|
||||||
Ok(head)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Unary {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Unary { kind, tail } = self;
|
|
||||||
match kind {
|
|
||||||
UnaryKind::Deref => {
|
|
||||||
let tail = tail.infer(e)?;
|
|
||||||
// TODO: get the base type
|
|
||||||
match e.entry(tail).ty() {
|
|
||||||
Some(&TypeKind::Ref(h)) => Ok(h),
|
|
||||||
other => todo!("Deref {other:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UnaryKind::Loop => {
|
|
||||||
let mut e = e.block_scope();
|
|
||||||
// Enter a new breakset
|
|
||||||
let mut e = e.open_bset();
|
|
||||||
|
|
||||||
// Infer the fail branch
|
|
||||||
let tail = tail.infer(&mut e)?;
|
|
||||||
// Unify the pass branch with Empty
|
|
||||||
let empt = e.empty();
|
|
||||||
e.unify(tail, empt)?;
|
|
||||||
|
|
||||||
// Return breakset
|
|
||||||
Ok(e.bset)
|
|
||||||
}
|
|
||||||
_op => {
|
|
||||||
// Infer the tail expression
|
|
||||||
let tail = tail.infer(e)?;
|
|
||||||
// TODO: Search within the tail type for `(op)`
|
|
||||||
Ok(tail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Member {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Member { head, kind } = self;
|
|
||||||
// Infer the head expression
|
|
||||||
let head = head.infer(e)?;
|
|
||||||
// Get the type of head
|
|
||||||
let head = e.prune(head);
|
|
||||||
let ty = e.entry(head);
|
|
||||||
// Search within the head type for the memberkind
|
|
||||||
match kind {
|
|
||||||
MemberKind::Call(name, tuple) => {
|
|
||||||
if let Some((args, rety)) = e.get_fn(ty.id(), *name) {
|
|
||||||
let values = iter::once(Ok(e.new_ref(head)))
|
|
||||||
// infer for each member-
|
|
||||||
.chain(tuple.exprs.iter().map(|expr| expr.infer(e)))
|
|
||||||
// Construct tuple
|
|
||||||
.collect::<Result<Vec<_>, InferenceError>>()
|
|
||||||
// Return tuple
|
|
||||||
.map(|tys| e.new_tuple(tys))?;
|
|
||||||
e.unify(args, values)?;
|
|
||||||
Ok(rety)
|
|
||||||
} else {
|
|
||||||
Err(InferenceError::NotFound(Path::from(*name)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberKind::Struct(name) => match ty.nav(&[PathPart::Ident(*name)]) {
|
|
||||||
Some(ty) => Ok(ty.id()),
|
|
||||||
None => Err(InferenceError::NotFound(Path::from(*name))),
|
|
||||||
},
|
|
||||||
MemberKind::Tuple(Literal::Int(idx)) => match ty.ty() {
|
|
||||||
Some(TypeKind::Tuple(tys)) => tys
|
|
||||||
.get(*idx as usize)
|
|
||||||
.copied()
|
|
||||||
.ok_or(InferenceError::FieldCount(head, tys.len(), *idx as usize)),
|
|
||||||
Some(TypeKind::Adt(Adt::TupleStruct(tys))) => tys
|
|
||||||
.get(*idx as usize)
|
|
||||||
.map(|(_vis, ty)| *ty)
|
|
||||||
.ok_or(InferenceError::FieldCount(head, tys.len(), *idx as usize)),
|
|
||||||
_ => Err(InferenceError::Mismatch(ty.id(), e.table.root())),
|
|
||||||
},
|
|
||||||
_ => Err(InferenceError::Mismatch(ty.id(), ty.root())),
|
|
||||||
}
|
|
||||||
// Type is required to be inferred at this point.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Index {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Index { head, indices } = self;
|
|
||||||
let usize = e.usize();
|
|
||||||
// Infer the head expression
|
|
||||||
let head = head.infer(e)?;
|
|
||||||
let mut head = e.prune(head);
|
|
||||||
// For each index expression:
|
|
||||||
for index in indices {
|
|
||||||
// Infer the index type
|
|
||||||
let index = index.infer(e)?;
|
|
||||||
if let Some((args, rety)) = e.get_fn(head, "index".into()) {
|
|
||||||
// Unify args and tuple (&head, index)
|
|
||||||
let selfty = e.new_ref(head);
|
|
||||||
let tupty = e.new_tuple(vec![selfty, index]);
|
|
||||||
e.unify(args, tupty)?;
|
|
||||||
head = e.prune(rety);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Decide whether the head can be indexed by that type
|
|
||||||
// TODO: check for a `.index` method on the type
|
|
||||||
match e.entry(head).ty().unwrap() {
|
|
||||||
&TypeKind::Slice(handle) | &TypeKind::Array(handle, _) => {
|
|
||||||
e.unify(usize, index)?;
|
|
||||||
head = e.prune(handle);
|
|
||||||
}
|
|
||||||
other => todo!("Indexing on type {other}"),
|
|
||||||
}
|
|
||||||
// head = result of indexing head
|
|
||||||
}
|
|
||||||
Ok(head)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Cast {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Cast { head, ty } = self;
|
|
||||||
// Infer the head expression
|
|
||||||
let _head = head.infer(e)?;
|
|
||||||
// Evaluate the type
|
|
||||||
let ty = ty
|
|
||||||
.evaluate(e.table, e.at)
|
|
||||||
.map_err(InferenceError::AnnotationEval)?;
|
|
||||||
// Decide whether the type is castable
|
|
||||||
// TODO: not deciding is absolutely unsound!!!
|
|
||||||
// Return the type
|
|
||||||
Ok(ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Path {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
e.by_name(self)
|
|
||||||
.map_err(|_| InferenceError::NotFound(self.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Let {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Let { mutable: _, name, ty, init } = self;
|
|
||||||
let ty = match ty {
|
|
||||||
Some(ty) => ty
|
|
||||||
.evaluate(e.table, e.at)
|
|
||||||
.map_err(InferenceError::AnnotationEval)?,
|
|
||||||
None => e.new_var(),
|
|
||||||
};
|
|
||||||
// Infer the initializer
|
|
||||||
if let Some(init) = init {
|
|
||||||
// Unify the initializer and the ty
|
|
||||||
let initty = init.infer(e)?;
|
|
||||||
e.unify(ty, initty)?;
|
|
||||||
}
|
|
||||||
// Deep copy the ty, if it exists
|
|
||||||
let ty = e.deep_clone(ty);
|
|
||||||
// Enter a local scope (modifies the current scope)
|
|
||||||
e.local_scope();
|
|
||||||
// Infer the pattern
|
|
||||||
let patty = name.infer(e)?;
|
|
||||||
// Unify the pattern and the ty
|
|
||||||
e.unify(ty, patty)?;
|
|
||||||
// `if let` returns whether the pattern succeeded or not
|
|
||||||
Ok(e.bool())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Match {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Match { scrutinee, arms } = self;
|
|
||||||
// Infer the scrutinee
|
|
||||||
let scrutinee = scrutinee.infer(e)?;
|
|
||||||
|
|
||||||
let mut out = None;
|
|
||||||
// For each pattern:
|
|
||||||
for MatchArm(pat, expr) in arms {
|
|
||||||
let mut scope = e.block_scope();
|
|
||||||
// Infer the pattern
|
|
||||||
let pat = pat.infer(&mut scope)?;
|
|
||||||
// Unify it with the scrutinee
|
|
||||||
scope.unify(scrutinee, pat)?;
|
|
||||||
// Infer the Expr
|
|
||||||
let expr = expr.infer(&mut scope)?;
|
|
||||||
// Unify the expr with the out variable
|
|
||||||
match out {
|
|
||||||
Some(ty) => e.unify(ty, expr)?,
|
|
||||||
None => out = Some(expr),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Return out. If there are no arms, assume Never.
|
|
||||||
match out {
|
|
||||||
Some(ty) => Ok(ty),
|
|
||||||
None => Ok(e.never()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Pattern {
|
|
||||||
// TODO: This is the wrong way to typeck pattern matching.
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
match self {
|
|
||||||
Pattern::Name(name) => {
|
|
||||||
// Evaluating a pattern creates and enters a new scope.
|
|
||||||
// Surely this will cause zero problems.
|
|
||||||
let node = e.table.new_entry(e.at, NodeKind::Local);
|
|
||||||
e.table.set_ty(node, TypeKind::Variable);
|
|
||||||
e.table.add_child(e.at, *name, node);
|
|
||||||
e.at = node;
|
|
||||||
Ok(node)
|
|
||||||
}
|
|
||||||
Pattern::Path(path) => {
|
|
||||||
// Evaluating a path pattern puts type constraints on the scrutinee
|
|
||||||
path.evaluate(e.table, e.at)
|
|
||||||
.map_err(|_| InferenceError::NotFound(path.clone()))
|
|
||||||
}
|
|
||||||
Pattern::Literal(literal) => literal.infer(e),
|
|
||||||
Pattern::Rest(Some(pat)) => pat.infer(e), // <-- glaring soundness holes
|
|
||||||
Pattern::Rest(_) => todo!("Fix glaring soundness holes in pattern"),
|
|
||||||
Pattern::Ref(_, pattern) => {
|
|
||||||
let ty = pattern.infer(e)?;
|
|
||||||
Ok(e.new_ref(ty))
|
|
||||||
}
|
|
||||||
Pattern::RangeExc(pat1, pat2) => {
|
|
||||||
let ty1 = pat1.infer(e)?;
|
|
||||||
let ty2 = pat2.infer(e)?;
|
|
||||||
e.unify(ty1, ty2)?;
|
|
||||||
Ok(ty1)
|
|
||||||
}
|
|
||||||
Pattern::RangeInc(pat1, pat2) => {
|
|
||||||
let ty1 = pat1.infer(e)?;
|
|
||||||
let ty2 = pat2.infer(e)?;
|
|
||||||
e.unify(ty1, ty2)?;
|
|
||||||
Ok(ty1)
|
|
||||||
}
|
|
||||||
Pattern::Tuple(patterns) => {
|
|
||||||
let tys = patterns
|
|
||||||
.iter()
|
|
||||||
.map(|pat| pat.infer(e))
|
|
||||||
.collect::<Result<Vec<Handle>, InferenceError>>()?;
|
|
||||||
Ok(e.new_tuple(tys))
|
|
||||||
}
|
|
||||||
Pattern::Array(patterns) => match patterns.as_slice() {
|
|
||||||
// TODO: rest patterns here
|
|
||||||
[one, rest @ ..] => {
|
|
||||||
let ty = one.infer(e)?;
|
|
||||||
for rest in rest {
|
|
||||||
let ty2 = rest.infer(e)?;
|
|
||||||
e.unify(ty, ty2)?;
|
|
||||||
}
|
|
||||||
Ok(e.new_slice(ty))
|
|
||||||
}
|
|
||||||
[] => {
|
|
||||||
let ty = e.new_var();
|
|
||||||
Ok(e.new_slice(ty))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Pattern::Struct(_path, _items) => todo!("Struct patterns"),
|
|
||||||
Pattern::TupleStruct(_path, _patterns) => todo!("Tuple struct patterns"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for While {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let While { cond, pass, fail } = self;
|
|
||||||
// Infer the condition
|
|
||||||
let cond = cond.infer(e)?;
|
|
||||||
// Unify the condition with bool
|
|
||||||
let bool = e.bool();
|
|
||||||
e.unify(bool, cond)?;
|
|
||||||
|
|
||||||
// Infer the fail branch
|
|
||||||
let fail = fail.infer(e)?;
|
|
||||||
// Unify the fail branch with breakset
|
|
||||||
let mut e = InferenceEngine { bset: fail, ..e.scoped() };
|
|
||||||
|
|
||||||
// Infer the pass branch
|
|
||||||
let pass = pass.infer(&mut e)?;
|
|
||||||
// Unify the pass branch with Empty
|
|
||||||
let empt = e.empty();
|
|
||||||
e.unify(pass, empt)?;
|
|
||||||
|
|
||||||
// Return breakset
|
|
||||||
Ok(e.bset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for If {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let If { cond, pass, fail } = self;
|
|
||||||
// Do inference on the condition'
|
|
||||||
let cond = cond.infer(e)?;
|
|
||||||
// Unify the condition with bool
|
|
||||||
let bool = e.bool();
|
|
||||||
e.unify(bool, cond)?;
|
|
||||||
// Do inference on the pass branch
|
|
||||||
let pass = pass.infer(e)?;
|
|
||||||
// Do inference on the fail branch
|
|
||||||
let fail = fail.infer(e)?;
|
|
||||||
// Unify pass and fail
|
|
||||||
e.unify(pass, fail)?;
|
|
||||||
// Return the result
|
|
||||||
Ok(pass)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for For {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let For { bind, cond, pass, fail } = self;
|
|
||||||
let mut e = e.block_scope();
|
|
||||||
|
|
||||||
let bind = bind.infer(&mut e)?;
|
|
||||||
|
|
||||||
// What does it mean to be iterable? Why, `next()`, of course!
|
|
||||||
let cond = cond.infer(&mut e)?;
|
|
||||||
let cond = e.prune(cond);
|
|
||||||
if let Some((args, rety)) = e.get_fn(cond, "next".into()) {
|
|
||||||
// Check that the args are correct
|
|
||||||
let params = vec![e.new_ref(cond)];
|
|
||||||
let params = e.new_tuple(params);
|
|
||||||
e.unify(args, params)?;
|
|
||||||
e.unify(rety, bind)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enter a new breakset
|
|
||||||
let mut e = e.open_bset();
|
|
||||||
|
|
||||||
// Infer the fail branch
|
|
||||||
let fail = fail.infer(&mut e)?;
|
|
||||||
// Unify the fail branch with breakset
|
|
||||||
let mut e = InferenceEngine { bset: fail, ..e.scoped() };
|
|
||||||
e.bset = fail;
|
|
||||||
|
|
||||||
// Infer the pass branch
|
|
||||||
let pass = pass.infer(&mut e)?;
|
|
||||||
// Unify the pass branch with Empty
|
|
||||||
let empt = e.empty();
|
|
||||||
e.unify(pass, empt)?;
|
|
||||||
|
|
||||||
// Return breakset
|
|
||||||
Ok(e.bset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Else {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
self.body.infer(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Break {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Break { body } = self;
|
|
||||||
// Infer the body of the break
|
|
||||||
let ty = body.infer(e)?;
|
|
||||||
// Unify it with the breakset of the loop
|
|
||||||
e.unify(ty, e.bset)?;
|
|
||||||
// Return never
|
|
||||||
Ok(e.never())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Return {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
let Return { body } = self;
|
|
||||||
// Infer the body of the return
|
|
||||||
let ty = body.infer(e)?;
|
|
||||||
// Unify it with the return-set of the function
|
|
||||||
e.unify(ty, e.rset)?;
|
|
||||||
// Return never
|
|
||||||
Ok(e.never())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, I: Inference<'a>> Inference<'a> for Option<I> {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
match self {
|
|
||||||
Some(expr) => expr.infer(e),
|
|
||||||
None => Ok(e.empty()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, I: Inference<'a>> Inference<'a> for Box<I> {
|
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
|
||||||
self.as_ref().infer(e)
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,12 +4,8 @@ use crate::{
|
|||||||
handle::Handle,
|
handle::Handle,
|
||||||
source::Source,
|
source::Source,
|
||||||
table::{NodeKind, Table},
|
table::{NodeKind, Table},
|
||||||
type_kind::TypeKind,
|
|
||||||
};
|
|
||||||
use cl_ast::{
|
|
||||||
ItemKind, Sym,
|
|
||||||
ast_visitor::{Visit, Walk},
|
|
||||||
};
|
};
|
||||||
|
use cl_ast::{ast_visitor::Visit, ItemKind, Sym};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Populator<'t, 'a> {
|
pub struct Populator<'t, 'a> {
|
||||||
@ -37,7 +33,7 @@ impl<'t, 'a> Populator<'t, 'a> {
|
|||||||
|
|
||||||
impl<'a> Visit<'a> for Populator<'_, 'a> {
|
impl<'a> Visit<'a> for Populator<'_, 'a> {
|
||||||
fn visit_item(&mut self, i: &'a cl_ast::Item) {
|
fn visit_item(&mut self, i: &'a cl_ast::Item) {
|
||||||
let cl_ast::Item { span, attrs, vis: _, kind } = i;
|
let cl_ast::Item { extents, attrs, vis, kind } = i;
|
||||||
// TODO: this, better, better.
|
// TODO: this, better, better.
|
||||||
let entry_kind = match kind {
|
let entry_kind = match kind {
|
||||||
ItemKind::Alias(_) => NodeKind::Type,
|
ItemKind::Alias(_) => NodeKind::Type,
|
||||||
@ -54,117 +50,82 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut entry = self.new_entry(entry_kind);
|
let mut entry = self.new_entry(entry_kind);
|
||||||
entry.inner.set_span(*span);
|
entry.inner.set_span(*extents);
|
||||||
entry.inner.set_meta(&attrs.meta);
|
entry.inner.set_meta(&attrs.meta);
|
||||||
|
|
||||||
entry.visit_children(i);
|
entry.visit_span(extents);
|
||||||
|
entry.visit_attrs(attrs);
|
||||||
|
entry.visit_visibility(vis);
|
||||||
|
entry.visit_item_kind(kind);
|
||||||
|
|
||||||
if let (Some(name), child) = (entry.name, entry.inner.id()) {
|
if let (Some(name), child) = (entry.name, entry.inner.id()) {
|
||||||
self.inner.add_child(name, child);
|
self.inner.add_child(name, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_generics(&mut self, value: &'a cl_ast::Generics) {
|
|
||||||
let cl_ast::Generics { vars } = value;
|
|
||||||
for var in vars {
|
|
||||||
let mut entry = self.inner.new_entry(NodeKind::Type);
|
|
||||||
entry.set_ty(TypeKind::Variable);
|
|
||||||
|
|
||||||
let id = entry.id();
|
|
||||||
self.inner.add_child(*var, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_alias(&mut self, a: &'a cl_ast::Alias) {
|
fn visit_alias(&mut self, a: &'a cl_ast::Alias) {
|
||||||
let cl_ast::Alias { name, from } = a;
|
let cl_ast::Alias { to, from } = a;
|
||||||
self.inner.set_source(Source::Alias(a));
|
self.inner.set_source(Source::Alias(a));
|
||||||
self.set_name(*name);
|
self.set_name(*to);
|
||||||
|
|
||||||
self.visit(from);
|
if let Some(t) = from {
|
||||||
|
self.visit_ty(t)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_const(&mut self, c: &'a cl_ast::Const) {
|
fn visit_const(&mut self, c: &'a cl_ast::Const) {
|
||||||
let cl_ast::Const { name, ty, init } = c;
|
let cl_ast::Const { name, ty, init } = c;
|
||||||
self.inner.set_source(Source::Const(c));
|
self.inner.set_source(Source::Const(c));
|
||||||
self.inner.set_body(init);
|
|
||||||
self.set_name(*name);
|
self.set_name(*name);
|
||||||
|
|
||||||
self.visit(ty);
|
self.visit_ty(ty);
|
||||||
self.visit(init);
|
self.visit_expr(init);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_static(&mut self, s: &'a cl_ast::Static) {
|
fn visit_static(&mut self, s: &'a cl_ast::Static) {
|
||||||
let cl_ast::Static { mutable, name, ty, init } = s;
|
let cl_ast::Static { mutable, name, ty, init } = s;
|
||||||
self.inner.set_source(Source::Static(s));
|
self.inner.set_source(Source::Static(s));
|
||||||
self.inner.set_body(init);
|
|
||||||
self.set_name(*name);
|
self.set_name(*name);
|
||||||
|
|
||||||
self.visit(mutable);
|
self.visit_mutability(mutable);
|
||||||
self.visit(ty);
|
self.visit_ty(ty);
|
||||||
self.visit(init);
|
self.visit_expr(init);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_module(&mut self, m: &'a cl_ast::Module) {
|
fn visit_module(&mut self, m: &'a cl_ast::Module) {
|
||||||
let cl_ast::Module { name, file } = m;
|
let cl_ast::Module { name, kind } = m;
|
||||||
self.inner.set_source(Source::Module(m));
|
self.inner.set_source(Source::Module(m));
|
||||||
self.set_name(*name);
|
self.set_name(*name);
|
||||||
|
|
||||||
self.visit(file);
|
self.visit_module_kind(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_function(&mut self, f: &'a cl_ast::Function) {
|
fn visit_function(&mut self, f: &'a cl_ast::Function) {
|
||||||
let cl_ast::Function { name, gens, sign, bind, body } = f;
|
let cl_ast::Function { name, sign, bind, body } = f;
|
||||||
// TODO: populate generics?
|
|
||||||
self.inner.set_source(Source::Function(f));
|
self.inner.set_source(Source::Function(f));
|
||||||
self.set_name(*name);
|
self.set_name(*name);
|
||||||
|
|
||||||
self.visit(gens);
|
self.visit_ty_fn(sign);
|
||||||
self.visit(sign);
|
bind.iter().for_each(|p| self.visit_param(p));
|
||||||
self.visit(bind);
|
|
||||||
|
|
||||||
if let Some(b) = body {
|
if let Some(b) = body {
|
||||||
self.inner.set_body(b);
|
self.visit_block(b)
|
||||||
self.visit(b);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_struct(&mut self, s: &'a cl_ast::Struct) {
|
fn visit_struct(&mut self, s: &'a cl_ast::Struct) {
|
||||||
let cl_ast::Struct { name, gens, kind } = s;
|
let cl_ast::Struct { name, kind } = s;
|
||||||
self.inner.set_source(Source::Struct(s));
|
self.inner.set_source(Source::Struct(s));
|
||||||
self.set_name(*name);
|
self.set_name(*name);
|
||||||
|
|
||||||
self.visit(gens);
|
self.visit_struct_kind(kind);
|
||||||
self.visit(kind);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_enum(&mut self, e: &'a cl_ast::Enum) {
|
fn visit_enum(&mut self, e: &'a cl_ast::Enum) {
|
||||||
let cl_ast::Enum { name, gens, variants } = e;
|
let cl_ast::Enum { name, kind } = e;
|
||||||
self.inner.set_source(Source::Enum(e));
|
self.inner.set_source(Source::Enum(e));
|
||||||
self.set_name(*name);
|
self.set_name(*name);
|
||||||
|
|
||||||
self.visit(gens);
|
self.visit_enum_kind(kind);
|
||||||
self.visit(variants);
|
|
||||||
let mut children = Vec::new();
|
|
||||||
for variant in variants.iter() {
|
|
||||||
let mut entry = self.new_entry(NodeKind::Type);
|
|
||||||
variant.visit_in(&mut entry);
|
|
||||||
children.push((variant.name, entry.inner.id()));
|
|
||||||
}
|
|
||||||
self.inner
|
|
||||||
.set_ty(TypeKind::Adt(crate::type_kind::Adt::Enum(children)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_variant(&mut self, value: &'a cl_ast::Variant) {
|
|
||||||
let cl_ast::Variant { name, kind, body } = value;
|
|
||||||
let mut entry = self.new_entry(NodeKind::Type);
|
|
||||||
entry.inner.set_source(Source::Variant(value));
|
|
||||||
entry.visit(kind);
|
|
||||||
if let Some(body) = body {
|
|
||||||
entry.inner.set_body(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
let child = entry.inner.id();
|
|
||||||
self.inner.add_child(*name, child);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_impl(&mut self, i: &'a cl_ast::Impl) {
|
fn visit_impl(&mut self, i: &'a cl_ast::Impl) {
|
||||||
@ -172,8 +133,8 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
|
|||||||
self.inner.set_source(Source::Impl(i));
|
self.inner.set_source(Source::Impl(i));
|
||||||
self.inner.mark_impl_item();
|
self.inner.mark_impl_item();
|
||||||
|
|
||||||
self.visit(target);
|
self.visit_impl_kind(target);
|
||||||
self.visit(body);
|
self.visit_file(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_use(&mut self, u: &'a cl_ast::Use) {
|
fn visit_use(&mut self, u: &'a cl_ast::Use) {
|
||||||
@ -181,6 +142,26 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
|
|||||||
self.inner.set_source(Source::Use(u));
|
self.inner.set_source(Source::Use(u));
|
||||||
self.inner.mark_use_item();
|
self.inner.mark_use_item();
|
||||||
|
|
||||||
self.visit(tree);
|
self.visit_use_tree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_let(&mut self, l: &'a cl_ast::Let) {
|
||||||
|
let cl_ast::Let { mutable, name: _, ty, init } = l;
|
||||||
|
let mut entry = self.new_entry(NodeKind::Local);
|
||||||
|
|
||||||
|
entry.inner.set_source(Source::Local(l));
|
||||||
|
// entry.set_name(*name);
|
||||||
|
|
||||||
|
entry.visit_mutability(mutable);
|
||||||
|
if let Some(ty) = ty {
|
||||||
|
entry.visit_ty(ty);
|
||||||
|
}
|
||||||
|
if let Some(init) = init {
|
||||||
|
entry.visit_expr(init)
|
||||||
|
}
|
||||||
|
|
||||||
|
// let child = entry.inner.id();
|
||||||
|
// self.inner.add_child(*name, child);
|
||||||
|
todo!("Pattern destructuring in cl-typeck")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ use crate::{
|
|||||||
source::Source,
|
source::Source,
|
||||||
type_kind::TypeKind,
|
type_kind::TypeKind,
|
||||||
};
|
};
|
||||||
use cl_ast::{Expr, Meta, PathPart, Sym};
|
use cl_ast::{Meta, PathPart, Sym};
|
||||||
use cl_structures::{index_map::IndexMap, span::Span};
|
use cl_structures::{index_map::IndexMap, span::Span};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -50,11 +50,11 @@ pub struct Table<'a> {
|
|||||||
pub(crate) children: HashMap<Handle, HashMap<Sym, Handle>>,
|
pub(crate) children: HashMap<Handle, HashMap<Sym, Handle>>,
|
||||||
pub(crate) imports: HashMap<Handle, HashMap<Sym, Handle>>,
|
pub(crate) imports: HashMap<Handle, HashMap<Sym, Handle>>,
|
||||||
pub(crate) use_items: HashMap<Handle, Vec<Handle>>,
|
pub(crate) use_items: HashMap<Handle, Vec<Handle>>,
|
||||||
bodies: HashMap<Handle, &'a Expr>,
|
|
||||||
types: HashMap<Handle, TypeKind>,
|
types: HashMap<Handle, TypeKind>,
|
||||||
spans: HashMap<Handle, Span>,
|
spans: HashMap<Handle, Span>,
|
||||||
metas: HashMap<Handle, &'a [Meta]>,
|
metas: HashMap<Handle, &'a [Meta]>,
|
||||||
sources: HashMap<Handle, Source<'a>>,
|
sources: HashMap<Handle, Source<'a>>,
|
||||||
|
// code: HashMap<Handle, BasicBlock>, // TODO: lower sources
|
||||||
impl_targets: HashMap<Handle, Handle>,
|
impl_targets: HashMap<Handle, Handle>,
|
||||||
anon_types: HashMap<TypeKind, Handle>,
|
anon_types: HashMap<TypeKind, Handle>,
|
||||||
|
|
||||||
@ -77,7 +77,6 @@ impl<'a> Table<'a> {
|
|||||||
children: HashMap::new(),
|
children: HashMap::new(),
|
||||||
imports: HashMap::new(),
|
imports: HashMap::new(),
|
||||||
use_items: HashMap::new(),
|
use_items: HashMap::new(),
|
||||||
bodies: HashMap::new(),
|
|
||||||
types: HashMap::new(),
|
types: HashMap::new(),
|
||||||
spans: HashMap::new(),
|
spans: HashMap::new(),
|
||||||
metas: HashMap::new(),
|
metas: HashMap::new(),
|
||||||
@ -121,7 +120,7 @@ impl<'a> Table<'a> {
|
|||||||
self.impls.push(item);
|
self.impls.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_iter(&mut self) -> impl Iterator<Item = Handle> + use<> {
|
pub fn handle_iter(&mut self) -> impl Iterator<Item = Handle> {
|
||||||
self.kinds.keys()
|
self.kinds.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,18 +142,6 @@ impl<'a> Table<'a> {
|
|||||||
entry
|
entry
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn inferred_type(&mut self) -> Handle {
|
|
||||||
let handle = self.new_entry(self.root, NodeKind::Type);
|
|
||||||
self.types.insert(handle, TypeKind::Inferred);
|
|
||||||
handle
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn type_variable(&mut self) -> Handle {
|
|
||||||
let handle = self.new_entry(self.root, NodeKind::Type);
|
|
||||||
self.types.insert(handle, TypeKind::Variable);
|
|
||||||
handle
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn root_entry(&self) -> Entry<'_, 'a> {
|
pub const fn root_entry(&self) -> Entry<'_, 'a> {
|
||||||
self.root.to_entry(self)
|
self.root.to_entry(self)
|
||||||
}
|
}
|
||||||
@ -185,10 +172,6 @@ impl<'a> Table<'a> {
|
|||||||
self.imports.get(&node)
|
self.imports.get(&node)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn body(&self, node: Handle) -> Option<&'a Expr> {
|
|
||||||
self.bodies.get(&node).copied()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ty(&self, node: Handle) -> Option<&TypeKind> {
|
pub fn ty(&self, node: Handle) -> Option<&TypeKind> {
|
||||||
self.types.get(&node)
|
self.types.get(&node)
|
||||||
}
|
}
|
||||||
@ -209,10 +192,6 @@ impl<'a> Table<'a> {
|
|||||||
self.impl_targets.get(&node).copied()
|
self.impl_targets.get(&node).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_body(&mut self, node: Handle, body: &'a Expr) -> Option<&'a Expr> {
|
|
||||||
self.bodies.insert(node, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_ty(&mut self, node: Handle, kind: TypeKind) -> Option<TypeKind> {
|
pub fn set_ty(&mut self, node: Handle, kind: TypeKind) -> Option<TypeKind> {
|
||||||
self.types.insert(node, kind)
|
self.types.insert(node, kind)
|
||||||
}
|
}
|
||||||
@ -245,14 +224,6 @@ impl<'a> Table<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn super_of(&self, node: Handle) -> Option<Handle> {
|
|
||||||
match self.kinds.get(node)? {
|
|
||||||
NodeKind::Root => None,
|
|
||||||
NodeKind::Module => self.parent(node).copied(),
|
|
||||||
_ => self.super_of(*self.parent(node)?),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self, node: Handle) -> Option<Sym> {
|
pub fn name(&self, node: Handle) -> Option<Sym> {
|
||||||
self.source(node).and_then(|s| s.name())
|
self.source(node).and_then(|s| s.name())
|
||||||
}
|
}
|
||||||
@ -288,7 +259,8 @@ impl<'a> Table<'a> {
|
|||||||
/// Does path traversal relative to the provided `node`.
|
/// Does path traversal relative to the provided `node`.
|
||||||
pub fn nav(&self, node: Handle, path: &[PathPart]) -> Option<Handle> {
|
pub fn nav(&self, node: Handle, path: &[PathPart]) -> Option<Handle> {
|
||||||
match path {
|
match path {
|
||||||
[PathPart::SuperKw, rest @ ..] => self.nav(self.super_of(node)?, rest),
|
[PathPart::SuperKw, rest @ ..] => self.nav(*self.parent(node)?, rest),
|
||||||
|
[PathPart::SelfKw, rest @ ..] => self.nav(node, rest),
|
||||||
[PathPart::SelfTy, rest @ ..] => self.nav(self.selfty(node)?, rest),
|
[PathPart::SelfTy, rest @ ..] => self.nav(self.selfty(node)?, rest),
|
||||||
[PathPart::Ident(name), rest @ ..] => self.nav(self.get_by_sym(node, name)?, rest),
|
[PathPart::Ident(name), rest @ ..] => self.nav(self.get_by_sym(node, name)?, rest),
|
||||||
[] => Some(node),
|
[] => Some(node),
|
||||||
@ -310,7 +282,6 @@ pub enum NodeKind {
|
|||||||
Const,
|
Const,
|
||||||
Static,
|
Static,
|
||||||
Function,
|
Function,
|
||||||
Temporary,
|
|
||||||
Local,
|
Local,
|
||||||
Impl,
|
Impl,
|
||||||
Use,
|
Use,
|
||||||
@ -328,7 +299,6 @@ mod display {
|
|||||||
NodeKind::Const => write!(f, "const"),
|
NodeKind::Const => write!(f, "const"),
|
||||||
NodeKind::Static => write!(f, "static"),
|
NodeKind::Static => write!(f, "static"),
|
||||||
NodeKind::Function => write!(f, "fn"),
|
NodeKind::Function => write!(f, "fn"),
|
||||||
NodeKind::Temporary => write!(f, "temp"),
|
|
||||||
NodeKind::Local => write!(f, "local"),
|
NodeKind::Local => write!(f, "local"),
|
||||||
NodeKind::Use => write!(f, "use"),
|
NodeKind::Use => write!(f, "use"),
|
||||||
NodeKind::Impl => write!(f, "impl"),
|
NodeKind::Impl => write!(f, "impl"),
|
||||||
|
@ -42,7 +42,6 @@ impl TypeExpression for TyKind {
|
|||||||
match self {
|
match self {
|
||||||
TyKind::Never => Ok(table.anon_type(TypeKind::Never)),
|
TyKind::Never => Ok(table.anon_type(TypeKind::Never)),
|
||||||
TyKind::Empty => Ok(table.anon_type(TypeKind::Empty)),
|
TyKind::Empty => Ok(table.anon_type(TypeKind::Empty)),
|
||||||
TyKind::Infer => Ok(table.inferred_type()),
|
|
||||||
TyKind::Path(p) => p.evaluate(table, node),
|
TyKind::Path(p) => p.evaluate(table, node),
|
||||||
TyKind::Array(a) => a.evaluate(table, node),
|
TyKind::Array(a) => a.evaluate(table, node),
|
||||||
TyKind::Slice(s) => s.evaluate(table, node),
|
TyKind::Slice(s) => s.evaluate(table, node),
|
||||||
|
@ -10,14 +10,10 @@ mod display;
|
|||||||
/// (a component of a [Table](crate::table::Table))
|
/// (a component of a [Table](crate::table::Table))
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum TypeKind {
|
pub enum TypeKind {
|
||||||
/// A type that is yet to be inferred!
|
|
||||||
Inferred,
|
|
||||||
/// A type variable, to be monomorphized
|
|
||||||
Variable,
|
|
||||||
/// An alias for an already-defined type
|
/// An alias for an already-defined type
|
||||||
Instance(Handle),
|
Instance(Handle),
|
||||||
/// A primitive type, built-in to the compiler
|
/// A primitive type, built-in to the compiler
|
||||||
Primitive(Primitive),
|
Intrinsic(Intrinsic),
|
||||||
/// A user-defined aromatic data type
|
/// A user-defined aromatic data type
|
||||||
Adt(Adt),
|
Adt(Adt),
|
||||||
/// A reference to an already-defined type: &T
|
/// A reference to an already-defined type: &T
|
||||||
@ -42,7 +38,7 @@ pub enum TypeKind {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Adt {
|
pub enum Adt {
|
||||||
/// A union-like enum type
|
/// A union-like enum type
|
||||||
Enum(Vec<(Sym, Handle)>),
|
Enum(Vec<(Sym, Option<Handle>)>),
|
||||||
|
|
||||||
/// A structural product type with named members
|
/// A structural product type with named members
|
||||||
Struct(Vec<(Sym, Visibility, Handle)>),
|
Struct(Vec<(Sym, Visibility, Handle)>),
|
||||||
@ -59,64 +55,42 @@ pub enum Adt {
|
|||||||
/// The set of compiler-intrinsic types.
|
/// The set of compiler-intrinsic types.
|
||||||
/// These primitive types have native implementations of the basic operations.
|
/// These primitive types have native implementations of the basic operations.
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Primitive {
|
pub enum Intrinsic {
|
||||||
I8, I16, I32, I64, I128, Isize, // Signed integers
|
I8, I16, I32, I64, I128, Isize, // Signed integers
|
||||||
U8, U16, U32, U64, U128, Usize, // Unsigned integers
|
U8, U16, U32, U64, U128, Usize, // Unsigned integers
|
||||||
F8, F16, F32, F64, F128, Fsize, // Floating point numbers
|
F8, F16, F32, F64, F128, Fsize, // Floating point numbers
|
||||||
Integer, Float, // Inferred int and float
|
|
||||||
Bool, // boolean value
|
Bool, // boolean value
|
||||||
Char, // Unicode codepoint
|
Char, // Unicode codepoint
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
impl Primitive {
|
|
||||||
/// Checks whether self is an integer
|
|
||||||
pub fn is_integer(self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
| Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 | Self::Isize
|
|
||||||
| Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::U128 | Self::Usize
|
|
||||||
| Self::Integer
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/// Checks whether self is a floating point number
|
|
||||||
pub fn is_float(self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
| Self::F8 | Self::F16 | Self::F32 | Self::F64 | Self::F128 | Self::Fsize
|
|
||||||
| Self::Float
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Author's note: the fsize type is a meme
|
// Author's note: the fsize type is a meme
|
||||||
|
|
||||||
impl FromStr for Primitive {
|
impl FromStr for Intrinsic {
|
||||||
type Err = ();
|
type Err = ();
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(match s {
|
Ok(match s {
|
||||||
"i8" => Primitive::I8,
|
"i8" => Intrinsic::I8,
|
||||||
"i16" => Primitive::I16,
|
"i16" => Intrinsic::I16,
|
||||||
"i32" => Primitive::I32,
|
"i32" => Intrinsic::I32,
|
||||||
"i64" => Primitive::I64,
|
"i64" => Intrinsic::I64,
|
||||||
"i128" => Primitive::I128,
|
"i128" => Intrinsic::I128,
|
||||||
"isize" => Primitive::Isize,
|
"isize" => Intrinsic::Isize,
|
||||||
"u8" => Primitive::U8,
|
"u8" => Intrinsic::U8,
|
||||||
"u16" => Primitive::U16,
|
"u16" => Intrinsic::U16,
|
||||||
"u32" => Primitive::U32,
|
"u32" => Intrinsic::U32,
|
||||||
"u64" => Primitive::U64,
|
"u64" => Intrinsic::U64,
|
||||||
"u128" => Primitive::U128,
|
"u128" => Intrinsic::U128,
|
||||||
"usize" => Primitive::Usize,
|
"usize" => Intrinsic::Usize,
|
||||||
"f8" => Primitive::F8,
|
"f8" => Intrinsic::F8,
|
||||||
"f16" => Primitive::F16,
|
"f16" => Intrinsic::F16,
|
||||||
"f32" => Primitive::F32,
|
"f32" => Intrinsic::F32,
|
||||||
"f64" => Primitive::F64,
|
"f64" => Intrinsic::F64,
|
||||||
"f128" => Primitive::F128,
|
"f128" => Intrinsic::F128,
|
||||||
"fsize" => Primitive::Fsize,
|
"fsize" => Intrinsic::Fsize,
|
||||||
"bool" => Primitive::Bool,
|
"bool" => Intrinsic::Bool,
|
||||||
"char" => Primitive::Char,
|
"char" => Intrinsic::Char,
|
||||||
_ => Err(())?,
|
_ => Err(())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! [Display] implementations for [TypeKind], [Adt], and [Intrinsic]
|
//! [Display] implementations for [TypeKind], [Adt], and [Intrinsic]
|
||||||
|
|
||||||
use super::{Adt, Primitive, TypeKind};
|
use super::{Adt, Intrinsic, TypeKind};
|
||||||
use crate::format_utils::*;
|
use crate::format_utils::*;
|
||||||
use cl_ast::format::FmtAdapter;
|
use cl_ast::format::FmtAdapter;
|
||||||
use std::fmt::{self, Display, Write};
|
use std::fmt::{self, Display, Write};
|
||||||
@ -8,10 +8,8 @@ use std::fmt::{self, Display, Write};
|
|||||||
impl Display for TypeKind {
|
impl Display for TypeKind {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TypeKind::Inferred => write!(f, "_"),
|
|
||||||
TypeKind::Variable => write!(f, "?"),
|
|
||||||
TypeKind::Instance(def) => write!(f, "alias to #{def}"),
|
TypeKind::Instance(def) => write!(f, "alias to #{def}"),
|
||||||
TypeKind::Primitive(i) => i.fmt(f),
|
TypeKind::Intrinsic(i) => i.fmt(f),
|
||||||
TypeKind::Adt(a) => a.fmt(f),
|
TypeKind::Adt(a) => a.fmt(f),
|
||||||
TypeKind::Ref(def) => write!(f, "&{def}"),
|
TypeKind::Ref(def) => write!(f, "&{def}"),
|
||||||
TypeKind::Slice(def) => write!(f, "slice [#{def}]"),
|
TypeKind::Slice(def) => write!(f, "slice [#{def}]"),
|
||||||
@ -38,7 +36,10 @@ impl Display for Adt {
|
|||||||
let mut variants = variants.iter();
|
let mut variants = variants.iter();
|
||||||
separate(", ", || {
|
separate(", ", || {
|
||||||
let (name, def) = variants.next()?;
|
let (name, def) = variants.next()?;
|
||||||
Some(move |f: &mut Delimit<_>| write!(f, "{name}: #{def}"))
|
Some(move |f: &mut Delimit<_>| match def {
|
||||||
|
Some(def) => write!(f, "{name}: #{def}"),
|
||||||
|
None => write!(f, "{name}"),
|
||||||
|
})
|
||||||
})(f.delimit_with("enum {", "}"))
|
})(f.delimit_with("enum {", "}"))
|
||||||
}
|
}
|
||||||
Adt::Struct(members) => {
|
Adt::Struct(members) => {
|
||||||
@ -67,31 +68,29 @@ impl Display for Adt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Primitive {
|
impl Display for Intrinsic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Primitive::I8 => f.write_str("i8"),
|
Intrinsic::I8 => f.write_str("i8"),
|
||||||
Primitive::I16 => f.write_str("i16"),
|
Intrinsic::I16 => f.write_str("i16"),
|
||||||
Primitive::I32 => f.write_str("i32"),
|
Intrinsic::I32 => f.write_str("i32"),
|
||||||
Primitive::I64 => f.write_str("i64"),
|
Intrinsic::I64 => f.write_str("i64"),
|
||||||
Primitive::I128 => f.write_str("i128"),
|
Intrinsic::I128 => f.write_str("i128"),
|
||||||
Primitive::Isize => f.write_str("isize"),
|
Intrinsic::Isize => f.write_str("isize"),
|
||||||
Primitive::U8 => f.write_str("u8"),
|
Intrinsic::U8 => f.write_str("u8"),
|
||||||
Primitive::U16 => f.write_str("u16"),
|
Intrinsic::U16 => f.write_str("u16"),
|
||||||
Primitive::U32 => f.write_str("u32"),
|
Intrinsic::U32 => f.write_str("u32"),
|
||||||
Primitive::U64 => f.write_str("u64"),
|
Intrinsic::U64 => f.write_str("u64"),
|
||||||
Primitive::U128 => f.write_str("u128"),
|
Intrinsic::U128 => f.write_str("u128"),
|
||||||
Primitive::Usize => f.write_str("usize"),
|
Intrinsic::Usize => f.write_str("usize"),
|
||||||
Primitive::F8 => f.write_str("f8"),
|
Intrinsic::F8 => f.write_str("f8"),
|
||||||
Primitive::F16 => f.write_str("f16"),
|
Intrinsic::F16 => f.write_str("f16"),
|
||||||
Primitive::F32 => f.write_str("f32"),
|
Intrinsic::F32 => f.write_str("f32"),
|
||||||
Primitive::F64 => f.write_str("f64"),
|
Intrinsic::F64 => f.write_str("f64"),
|
||||||
Primitive::F128 => f.write_str("f128"),
|
Intrinsic::F128 => f.write_str("f128"),
|
||||||
Primitive::Fsize => f.write_str("fsize"),
|
Intrinsic::Fsize => f.write_str("fsize"),
|
||||||
Primitive::Integer => f.write_str("{integer}"),
|
Intrinsic::Bool => f.write_str("bool"),
|
||||||
Primitive::Float => f.write_str("{float}"),
|
Intrinsic::Char => f.write_str("char"),
|
||||||
Primitive::Bool => f.write_str("bool"),
|
|
||||||
Primitive::Char => f.write_str("char"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
grammar.ebnf
13
grammar.ebnf
@ -26,7 +26,7 @@ Static = "static" Mutability Identifier ':' Ty '=' Expr ';' ;
|
|||||||
Module = "mod" Identifier ModuleKind ;
|
Module = "mod" Identifier ModuleKind ;
|
||||||
ModuleKind = '{' Item* '}' | ';' ;
|
ModuleKind = '{' Item* '}' | ';' ;
|
||||||
|
|
||||||
Function = "fn" Identifier '(' (Param ',')* Param? ')' ('->' Ty)? (Expr | ';') ;
|
Function = "fn" Identifier '(' (Param ',')* Param? ')' ('->' Ty)? Block? ;
|
||||||
Param = Mutability Identifier ':' Ty ;
|
Param = Mutability Identifier ':' Ty ;
|
||||||
|
|
||||||
Struct = "struct" Identifier (StructTuple | StructBody)?;
|
Struct = "struct" Identifier (StructTuple | StructBody)?;
|
||||||
@ -127,17 +127,6 @@ Block = '{' Stmt* '}';
|
|||||||
Group = Empty | '(' (Expr | Tuple) ')' ;
|
Group = Empty | '(' (Expr | Tuple) ')' ;
|
||||||
Tuple = (Expr ',')* Expr? ;
|
Tuple = (Expr ',')* Expr? ;
|
||||||
|
|
||||||
|
|
||||||
Match = "match" { (MatchArm ',')* MatchArm? } ;
|
|
||||||
MatchArm = Pattern '=>' Expr ;
|
|
||||||
Pattern = Path
|
|
||||||
| Literal
|
|
||||||
| '&' "mut"? Pattern
|
|
||||||
| '(' (Pattern ',')* (Pattern | '..' )? ')'
|
|
||||||
| '[' (Pattern ',')* (Pattern | '..' Identifier?)? ']'
|
|
||||||
| StructPattern
|
|
||||||
;
|
|
||||||
|
|
||||||
Loop = "loop" Block ;
|
Loop = "loop" Block ;
|
||||||
While = "while" Expr Block Else ;
|
While = "while" Expr Block Else ;
|
||||||
If = "if" Expr Block Else ;
|
If = "if" Expr Block Else ;
|
||||||
|
@ -112,17 +112,6 @@ impl<'a> Editor<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_err<W: Write>(&self, w: &mut W, err: impl Display) -> ReplResult<()> {
|
|
||||||
queue!(
|
|
||||||
w,
|
|
||||||
SavePosition,
|
|
||||||
Clear(ClearType::UntilNewLine),
|
|
||||||
Print(err),
|
|
||||||
RestorePosition
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prints the characters after the cursor on the current line.
|
/// Prints the characters after the cursor on the current line.
|
||||||
pub fn print_tail<W: Write>(&self, w: &mut W) -> ReplResult<()> {
|
pub fn print_tail<W: Write>(&self, w: &mut W) -> ReplResult<()> {
|
||||||
let Self { tail, .. } = self;
|
let Self { tail, .. } = self;
|
||||||
@ -237,18 +226,9 @@ impl<'a> Editor<'a> {
|
|||||||
self.head.len() + self.tail.len()
|
self.head.len() + self.tail.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the cursor is at the beginning
|
|
||||||
pub fn at_start(&self) -> bool {
|
|
||||||
self.head.is_empty()
|
|
||||||
}
|
|
||||||
/// Returns true if the cursor is at the end
|
|
||||||
pub fn at_end(&self) -> bool {
|
|
||||||
self.tail.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the buffer is empty.
|
/// Returns true if the buffer is empty.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.at_start() && self.at_end()
|
self.head.is_empty() && self.tail.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the buffer ends with a given pattern
|
/// Returns true if the buffer ends with a given pattern
|
||||||
|
@ -49,7 +49,7 @@ where F: FnMut(&str) -> Result<Response, Box<dyn Error>> {
|
|||||||
Ok(Response::Deny) => rl.deny(),
|
Ok(Response::Deny) => rl.deny(),
|
||||||
Ok(Response::Break) => break,
|
Ok(Response::Break) => break,
|
||||||
Ok(Response::Continue) => continue,
|
Ok(Response::Continue) => continue,
|
||||||
Err(e) => rl.print_inline(format_args!("\x1b[40G\x1b[91m{e}\x1b[0m"))?,
|
Err(e) => print!("\x1b[40G\x1b[A\x1bJ\x1b[91m{e}\x1b[0m\x1b[B"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
use crate::{editor::Editor, error::*, iter::*, raw::raw};
|
use crate::{editor::Editor, error::*, iter::*, raw::raw};
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
io::{Bytes, Read, Result, Write, stdout},
|
io::{stdout, Bytes, Read, Result, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Prompts the user, reads the lines. Not much more to it than that.
|
/// Prompts the user, reads the lines. Not much more to it than that.
|
||||||
@ -28,7 +28,6 @@ impl<'a> Repline<'a, std::io::Stdin> {
|
|||||||
impl<'a, R: Read> Repline<'a, R> {
|
impl<'a, R: Read> Repline<'a, R> {
|
||||||
/// Constructs a [Repline] with the given [Reader](Read), color, begin, and again prompts.
|
/// Constructs a [Repline] with the given [Reader](Read), color, begin, and again prompts.
|
||||||
pub fn with_input(input: R, color: &'a str, begin: &'a str, again: &'a str) -> Self {
|
pub fn with_input(input: R, color: &'a str, begin: &'a str, again: &'a str) -> Self {
|
||||||
#[allow(clippy::unbuffered_bytes)]
|
|
||||||
Self {
|
Self {
|
||||||
input: Chars(Flatten(input.bytes())),
|
input: Chars(Flatten(input.bytes())),
|
||||||
history: Default::default(),
|
history: Default::default(),
|
||||||
@ -81,12 +80,7 @@ impl<'a, R: Read> Repline<'a, R> {
|
|||||||
// ignore newlines, process line feeds. Not sure how cross-platform this is.
|
// ignore newlines, process line feeds. Not sure how cross-platform this is.
|
||||||
'\n' => {}
|
'\n' => {}
|
||||||
'\r' => {
|
'\r' => {
|
||||||
if self.ed.at_end() {
|
|
||||||
self.ed.push('\n', stdout)?;
|
self.ed.push('\n', stdout)?;
|
||||||
} else {
|
|
||||||
self.ed.end(stdout)?;
|
|
||||||
writeln!(stdout)?;
|
|
||||||
}
|
|
||||||
return Ok(self.ed.to_string());
|
return Ok(self.ed.to_string());
|
||||||
}
|
}
|
||||||
// Ctrl+Backspace in my terminal
|
// Ctrl+Backspace in my terminal
|
||||||
@ -117,15 +111,6 @@ impl<'a, R: Read> Repline<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Prints a message without moving the cursor
|
|
||||||
pub fn print_inline(&mut self, value: impl std::fmt::Display) -> ReplResult<()> {
|
|
||||||
let mut stdout = stdout().lock();
|
|
||||||
self.print_err(&mut stdout, value)
|
|
||||||
}
|
|
||||||
/// Prints a message (ideally an error) without moving the cursor
|
|
||||||
fn print_err<W: Write>(&mut self, w: &mut W, value: impl std::fmt::Display) -> ReplResult<()> {
|
|
||||||
self.ed.print_err(w, value)
|
|
||||||
}
|
|
||||||
/// Handle ANSI Escape
|
/// Handle ANSI Escape
|
||||||
fn escape<W: Write>(&mut self, w: &mut W) -> ReplResult<()> {
|
fn escape<W: Write>(&mut self, w: &mut W) -> ReplResult<()> {
|
||||||
match self.input.next().ok_or(Error::EndOfInput)?? {
|
match self.input.next().ok_or(Error::EndOfInput)?? {
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
#!/usr/bin/env -S conlang-run
|
|
||||||
//! A simple five-function pn calculator
|
|
||||||
|
|
||||||
// TODO: enum constructors in the interpreter
|
|
||||||
struct Atom(f64);
|
|
||||||
struct Op(char, [Expr]);
|
|
||||||
|
|
||||||
enum Expr {
|
|
||||||
Atom(f64),
|
|
||||||
Op(char, [Expr]),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Evaluates an expression
|
|
||||||
fn eval(expr: Expr) -> isize {
|
|
||||||
match expr {
|
|
||||||
Atom(value) => value,
|
|
||||||
Op('*', [lhs, rhs]) => eval(lhs) * eval(rhs),
|
|
||||||
Op('/', [lhs, rhs]) => eval(lhs) / eval(rhs),
|
|
||||||
Op('%', [lhs, rhs]) => eval(lhs) % eval(rhs),
|
|
||||||
Op('+', [lhs, rhs]) => eval(lhs) + eval(rhs),
|
|
||||||
Op('-', [lhs, rhs]) => eval(lhs) - eval(rhs),
|
|
||||||
Op('-', [lhs]) => - eval(lhs),
|
|
||||||
Op(other, ..rest) => {
|
|
||||||
panic("ERROR: Unknown operator: " + other)
|
|
||||||
},
|
|
||||||
other => {
|
|
||||||
println(other);
|
|
||||||
panic("ERROR: Unknown operation ^")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Parses expressions
|
|
||||||
fn parse(line: [char], power: i32) -> (Expr, [char]) {
|
|
||||||
fn map((expr, line): (Expr, [char]), f: fn(Expr) -> Expr) -> (Expr, [char]) {
|
|
||||||
(f(expr), line)
|
|
||||||
}
|
|
||||||
|
|
||||||
line = space(line);
|
|
||||||
|
|
||||||
let (lhs, line) = match line {
|
|
||||||
['0'..='9', ..] => number(line),
|
|
||||||
[op, ..rest] => {
|
|
||||||
parse(rest, pre_bp(op)).map(|lhs| Op(op, [lhs]))
|
|
||||||
},
|
|
||||||
_ => panic("Unexpected end of input"),
|
|
||||||
};
|
|
||||||
|
|
||||||
while let [op, ..rest] = space(line) {
|
|
||||||
let (before, after) = inf_bp(op);
|
|
||||||
if before < power {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
(lhs, line) = parse(rest, after).map(|rhs| Op(op, [lhs, rhs]));
|
|
||||||
};
|
|
||||||
(lhs, line)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn number(line: [char]) -> (Expr, [char]) {
|
|
||||||
let value = 0.0;
|
|
||||||
while (let [first, ..rest] = line) && (let '0'..='9' = first) {
|
|
||||||
value = value * 10.0 + (first as f64 - '0' as f64);
|
|
||||||
line = rest;
|
|
||||||
};
|
|
||||||
(Atom(value), line)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn space(line: [char]) -> [char] {
|
|
||||||
match line {
|
|
||||||
[' ', ..rest] => space(rest),
|
|
||||||
line => line
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inf_bp(op: char) -> (i32, i32) {
|
|
||||||
(|x| (2 * x, 2 * x + 1))(
|
|
||||||
match op {
|
|
||||||
'*' => 2,
|
|
||||||
'/' => 2,
|
|
||||||
'%' => 2,
|
|
||||||
'+' => 1,
|
|
||||||
'-' => 1,
|
|
||||||
_ => -1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pre_bp(op: char) -> i32 {
|
|
||||||
(|x| 2 * x + 1)(
|
|
||||||
match op {
|
|
||||||
'-' => 9,
|
|
||||||
_ => -1,
|
|
||||||
})
|
|
||||||
}
|
|
5
sample-code/hello.tp
Normal file
5
sample-code/hello.tp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
// The main function
|
||||||
|
nasin wan () {
|
||||||
|
toki_linja("mi toki ale a!")
|
||||||
|
}
|
@ -6,13 +6,13 @@ struct Student {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn Student (name: str, age: i32) -> Student {
|
fn Student (name: str, age: i32) -> Student {
|
||||||
Student { name, age }
|
Student: { name, age }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_test(student: Student) {
|
fn match_test(student: Student) {
|
||||||
match student {
|
match student {
|
||||||
Student { name: "shark", age } => println("Found a shark of ", age, " year(s)"),
|
Student: { name: "shark", age } => println("Found a shark of ", age, " year(s)"),
|
||||||
Student { name, age: 22 } => println("Found a 22-year-old named ", name),
|
Student: { name, age: 22 } => println("Found a 22-year-old named ", name),
|
||||||
Student { name, age } => println("Found someone named ", name, " of ", age, " year(s)"),
|
Student: { name, age } => println("Found someone named ", name, " of ", age, " year(s)"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
sample-code/pona.tp
Normal file
10
sample-code/pona.tp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//! toki!
|
||||||
|
|
||||||
|
nasin toki_pona(nimi: linja) -> linja {
|
||||||
|
seme nimi {
|
||||||
|
"a" => "PARTICLE: Emphasis or emotion",
|
||||||
|
_ => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kiwen main: nasin(Linja) -> Linja = toki_pona;
|
@ -1,8 +0,0 @@
|
|||||||
//! Implements a Truth Machine
|
|
||||||
|
|
||||||
fn main (n)
|
|
||||||
match n {
|
|
||||||
1 => loop print(1),
|
|
||||||
n => println(n),
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
|||||||
//! Disjoint Set Forest implementation of the Union Find algorithm
|
|
||||||
|
|
||||||
// enum TreeNode {
|
|
||||||
// Empty,
|
|
||||||
// Filled { parent: usize, rank: usize }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: Namespace based on type of first argument
|
|
||||||
|
|
||||||
fn makeset(f, x) {
|
|
||||||
match (*f)[x] {
|
|
||||||
() => (*f)[x] = Filled { parent: x, rank: 0 },
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn union(f, a, b) {
|
|
||||||
let (a, b) = (find(f, a), find(f, b));
|
|
||||||
if a == b { return; }
|
|
||||||
match ((*f)[a], (*f)[b]) {
|
|
||||||
(Filled {parent: _, rank: r_a}, Filled {parent: _, rank: r_b}) => {
|
|
||||||
if r_a < r_b {
|
|
||||||
union(f, b, a)
|
|
||||||
} else {
|
|
||||||
(*f)[b].parent = a;
|
|
||||||
(*f)[a].rank += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find(f, x) {
|
|
||||||
match (*f)[x] {
|
|
||||||
Filled { parent, rank } => if parent == x {
|
|
||||||
x
|
|
||||||
} else {
|
|
||||||
let parent = find(f, parent);
|
|
||||||
(*f)[x].parent = parent;
|
|
||||||
parent
|
|
||||||
},
|
|
||||||
() => x,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show(f) {
|
|
||||||
for node in 0..(len((*f))) {
|
|
||||||
match (*f)[node] {
|
|
||||||
Filled { parent, rank } => println(node, ": { parent: ", parent, ", rank: ", rank, " }"),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test(f) {
|
|
||||||
"Union Find on Disjoint Set Forest".println()
|
|
||||||
for i in 0..10 { makeset(f, i) }
|
|
||||||
for i in 10..20 { makeset(f, i) }
|
|
||||||
show(f)
|
|
||||||
println()
|
|
||||||
|
|
||||||
for i in 1..10 { union(f, i*2-1, i*2) }
|
|
||||||
for i in 5..10 { union(f, i*2+1, i*2) }
|
|
||||||
show(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let f = [();20]
|
|
||||||
f.test()
|
|
||||||
}
|
|
@ -1,24 +1,12 @@
|
|||||||
//! # The Conlang Standard Library
|
//! # The Conlang Standard Library
|
||||||
|
|
||||||
pub mod preamble {
|
pub mod preamble {
|
||||||
pub use super::{
|
pub use super::{num::*, str::str};
|
||||||
num::*,
|
|
||||||
option::Option,
|
|
||||||
range::{RangeExc, RangeInc},
|
|
||||||
result::Result,
|
|
||||||
str::str,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod num;
|
pub mod num;
|
||||||
|
|
||||||
pub mod str;
|
pub mod str;
|
||||||
|
|
||||||
pub mod option;
|
|
||||||
|
|
||||||
pub mod result;
|
|
||||||
|
|
||||||
pub mod range;
|
|
||||||
|
|
||||||
#[cfg("test")]
|
#[cfg("test")]
|
||||||
mod test;
|
mod test;
|
||||||
|
@ -1,51 +1,51 @@
|
|||||||
//! The primitive numeric types
|
//! The primitive numeric types
|
||||||
|
|
||||||
#[lang = "bool"]
|
#[intrinsic = "bool"]
|
||||||
pub type bool;
|
pub type bool;
|
||||||
|
|
||||||
#[lang = "char"]
|
#[intrinsic = "char"]
|
||||||
pub type char;
|
pub type char;
|
||||||
|
|
||||||
#[lang = "i8"]
|
#[intrinsic = "i8"]
|
||||||
pub type i8;
|
pub type i8;
|
||||||
|
|
||||||
#[lang = "i16"]
|
#[intrinsic = "i16"]
|
||||||
pub type i16;
|
pub type i16;
|
||||||
|
|
||||||
#[lang = "i32"]
|
#[intrinsic = "i32"]
|
||||||
pub type i32;
|
pub type i32;
|
||||||
|
|
||||||
#[lang = "i64"]
|
#[intrinsic = "i64"]
|
||||||
pub type i64;
|
pub type i64;
|
||||||
|
|
||||||
#[lang = "i128"]
|
#[intrinsic = "i128"]
|
||||||
pub type i128;
|
pub type i128;
|
||||||
|
|
||||||
#[lang = "isize"]
|
#[intrinsic = "isize"]
|
||||||
pub type isize;
|
pub type isize;
|
||||||
|
|
||||||
#[lang = "u8"]
|
#[intrinsic = "u8"]
|
||||||
pub type u8;
|
pub type u8;
|
||||||
|
|
||||||
#[lang = "u16"]
|
#[intrinsic = "u16"]
|
||||||
pub type u16;
|
pub type u16;
|
||||||
|
|
||||||
#[lang = "u32"]
|
#[intrinsic = "u32"]
|
||||||
pub type u32;
|
pub type u32;
|
||||||
|
|
||||||
#[lang = "u64"]
|
#[intrinsic = "u64"]
|
||||||
pub type u64;
|
pub type u64;
|
||||||
|
|
||||||
#[lang = "u128"]
|
#[intrinsic = "u128"]
|
||||||
pub type u128;
|
pub type u128;
|
||||||
|
|
||||||
#[lang = "usize"]
|
#[intrinsic = "usize"]
|
||||||
pub type usize;
|
pub type usize;
|
||||||
|
|
||||||
#[lang = "f32"]
|
#[intrinsic = "f32"]
|
||||||
pub type f32;
|
pub type f32;
|
||||||
|
|
||||||
#[lang = "f64"]
|
#[intrinsic = "f64"]
|
||||||
pub type f64;
|
pub type f64;
|
||||||
|
|
||||||
// Contains implementations for (TODO) overloaded operators on num types
|
// Contains implementations for (TODO) overloaded operators on num types
|
||||||
@ -278,9 +278,9 @@ pub mod ops {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl usize {
|
impl usize {
|
||||||
pub const MIN: Self = (); // __march_ptr_width_unsigned_min(); // TODO: intrinsics
|
pub const MIN: Self = __march_ptr_width_unsigned_min();
|
||||||
pub const MAX: Self = (); // __march_ptr_width_unsigned_max(); // TODO: intrinsics
|
pub const MAX: Self = __march_ptr_width_unsigned_max();
|
||||||
pub const BIT_WIDTH: u32 = (); // __march_ptr_width_bits(); // TODO: intrinsics
|
pub const BIT_WIDTH: u32 = __march_ptr_width_bits();
|
||||||
pub fn default() -> Self {
|
pub fn default() -> Self {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@ -512,9 +512,9 @@ pub mod ops {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl isize {
|
impl isize {
|
||||||
pub const MIN: Self = (); // __march_ptr_width_signed_min(); // TODO: intrinsics
|
pub const MIN: Self = __march_ptr_width_signed_min();
|
||||||
pub const MAX: Self = (); // __march_ptr_width_signed_max(); // TODO: intrinsics
|
pub const MAX: Self = __march_ptr_width_signed_max();
|
||||||
pub const BIT_WIDTH: u32 = (); // __march_ptr_width_bits(); // TODO: intrinsics
|
pub const BIT_WIDTH: u32 = __march_ptr_width_bits();
|
||||||
pub fn default() -> Self {
|
pub fn default() -> Self {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
//! The optional type, representing the presence or absence of a thing.
|
|
||||||
use super::preamble::*;
|
|
||||||
|
|
||||||
pub enum Option<T> {
|
|
||||||
Some(T),
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Option {
|
|
||||||
pub fn is_some(self: &Self) -> bool {
|
|
||||||
match self {
|
|
||||||
Some(_) => true,
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn is_none(self: &Self) -> bool {
|
|
||||||
match self {
|
|
||||||
Some(_) => false,
|
|
||||||
None => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Maps from one option space to another
|
|
||||||
// pub fn map<U>(self: Self, f: fn(T) -> U) -> Option<U> {
|
|
||||||
// match self {
|
|
||||||
// Some(value) => Some(f(value)),
|
|
||||||
// None => None,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
//! Iterable ranges
|
|
||||||
|
|
||||||
/// An Exclusive Range `a .. b` iterates from a to b, excluding b
|
|
||||||
// #[lang = "range_exc"]
|
|
||||||
pub struct RangeExc<T>(T, T)
|
|
||||||
|
|
||||||
/// An Inclusive Range `a ..= b` iterates from a to b, including b
|
|
||||||
// #[lang = "range_inc"]
|
|
||||||
pub struct RangeInc<T>(T, T)
|
|
||||||
|
|
||||||
impl RangeExc {
|
|
||||||
fn next<T>(this: &RangeExc) -> T {
|
|
||||||
(*this).0
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
//! The Result type, indicating a fallible operation.
|
|
||||||
use super::preamble::*;
|
|
||||||
|
|
||||||
pub enum Result<T, E> {
|
|
||||||
Ok(T),
|
|
||||||
Err(E),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Result {
|
|
||||||
pub fn is_ok(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Ok(_) => true,
|
|
||||||
Err(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn is_err(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Ok(_) => false,
|
|
||||||
Err(_) => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Maps the value inside the Result::Ok, leaving errors alone.
|
|
||||||
// pub fn map<U>(self, f: fn(T) -> U) -> Result<U, E> {
|
|
||||||
// match self {
|
|
||||||
// Ok(t) => Ok(f(t)),
|
|
||||||
// Err(e) => Err(e),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
/// Maps the value inside the Result::Err, leaving values alone.
|
|
||||||
// pub fn map_err<F>(self, f: fn(E) -> F) -> Result<T, F> {
|
|
||||||
// match self {
|
|
||||||
// Ok(t) => Ok(t),
|
|
||||||
// Err(e) => Err(f(e)),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
//! TODO: give conland a string type
|
//! TODO: give conland a string type
|
||||||
use super::num::u8;
|
use super::num::u8;
|
||||||
|
|
||||||
// #[lang = "str"]
|
|
||||||
type str = [u8];
|
type str = [u8];
|
||||||
|
@ -4,14 +4,14 @@ use super::preamble::*;
|
|||||||
|
|
||||||
struct UnitLike;
|
struct UnitLike;
|
||||||
|
|
||||||
struct TupleLike(super::num::i32, super::test::char)
|
struct TupleLike(super::num::i32, super::self::test::char)
|
||||||
|
|
||||||
struct StructLike {
|
struct StructLike {
|
||||||
pub member1: UnitLike,
|
pub member1: UnitLike,
|
||||||
member2: TupleLike,
|
member2: TupleLike,
|
||||||
}
|
}
|
||||||
|
|
||||||
// enum NeverLike;
|
enum NeverLike;
|
||||||
|
|
||||||
enum EmptyLike {
|
enum EmptyLike {
|
||||||
Empty,
|
Empty,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user