diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..c819326 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,9 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.217.4/containers/rust/.devcontainer/base.Dockerfile + +# [Choice] Debian OS version (use bullseye on local arm64/Apple Silicon): buster, bullseye +ARG VARIANT="buster" +FROM mcr.microsoft.com/vscode/devcontainers/rust:0-${VARIANT} + +# [Optional] Uncomment this section to install additional packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..32b3c13 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.217.4/containers/rust +{ + "name": "Rust", + "build": { + "dockerfile": "Dockerfile", + "args": { + // Use the VARIANT arg to pick a Debian OS version: buster, bullseye + // Use bullseye when on local on arm64/Apple Silicon. + "VARIANT": "buster" + } + }, + "runArgs": [ + "--cap-add=SYS_PTRACE", + "--security-opt", + "seccomp=unconfined" + ], + + // Set *default* container specific settings.json values on container create. + "settings": { + "lldb.executable": "/usr/bin/lldb", + // VS Code don't watch files under ./target + "files.watcherExclude": { + "**/target/**": true + }, + "rust-analyzer.checkOnSave.command": "clippy" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "vadimcn.vscode-lldb", + "mutantdino.resourcemonitor", + "matklad.rust-analyzer", + "tamasfe.even-better-toml", + "serayuzgur.crates" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "rustc --version", + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} diff --git a/src/item.rs b/src/item.rs index 5f6fb62..c01f573 100644 --- a/src/item.rs +++ b/src/item.rs @@ -5,6 +5,7 @@ use crate::r#enum::Enum; use crate::r#impl::Impl; use crate::r#struct::Struct; use crate::r#trait::Trait; +use crate::type_alias::TypeAlias; #[derive(Debug, Clone)] pub enum Item { @@ -15,4 +16,5 @@ pub enum Item { Enum(Enum), Impl(Impl), Raw(String), + TypeAlias(TypeAlias), } diff --git a/src/keywords.rs b/src/keywords.rs new file mode 100644 index 0000000..434f64f --- /dev/null +++ b/src/keywords.rs @@ -0,0 +1,73 @@ +const KW_AS: &str = "as"; +const KW_BREAK: &str = "break"; +const KW_CONST: &str = "const"; +const KW_CONTINUE: &str = "continue"; +const KW_CRATE: &str = "crate"; +const KW_ELSE: &str = "else"; +const KW_ENUM: &str = "enum"; +const KW_EXTERN: &str = "extern"; +const KW_FALSE: &str = "false"; +const KW_FN: &str = "fn"; +const KW_FOR: &str = "for"; +const KW_IF: &str = "if"; +const KW_IMPL: &str = "impl"; +const KW_IN: &str = "in"; +const KW_LET: &str = "let"; +const KW_LOOP: &str = "loop"; +const KW_MATCH: &str = "match"; +const KW_MOD: &str = "mod"; +const KW_MOVE: &str = "move"; +const KW_MUT: &str = "mut"; +const KW_PUB: &str = "pub"; +const KW_REF: &str = "ref"; +const KW_RETURN: &str = "return"; +const KW_SELFVALUE: &str = "self"; +const KW_SELFTYPE: &str = "Self"; +const KW_STATIC: &str = "static"; +const KW_STRUCT: &str = "struct"; +const KW_SUPER: &str = "super"; +const KW_TRAIT: &str = "trait"; +const KW_TRUE: &str = "true"; +const KW_TYPE: &str = "type"; +const KW_UNSAFE: &str = "unsafe"; +const KW_USE: &str = "use"; +const KW_WHERE: &str = "where"; +const KW_WHILE: &str = "while"; + +const KEYWORDS_STRICT: [&str] = [ + KW_AS, + KW_BREAK, + KW_CONST, + KW_CONTINUE, + KW_CRATE, + KW_ELSE, + KW_ENUM, + KW_EXTERN, + KW_FALSE, + KW_FN, + KW_FOR, + KW_IF, + KW_IMPL, + KW_IN, + KW_LET, + KW_LOOP, + KW_MATCH, + KW_MOD, + KW_MOVE, + KW_MUT, + KW_PUB, + KW_REF, + KW_RETURN, + KW_SELFVALUE, + KW_SELFTYPE, + KW_STATIC, + KW_STRUCT, + KW_SUPER, + KW_TRAIT, + KW_TRUE, + KW_TYPE, + KW_UNSAFE, + KW_USE, + KW_WHERE, + KW_WHILE, +]; diff --git a/src/lib.rs b/src/lib.rs index 70b8675..9920108 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ mod r#impl; mod r#struct; mod r#trait; mod r#type; - +mod type_alias; pub use associated_type::*; pub use block::*; diff --git a/src/scope.rs b/src/scope.rs index 1312139..a1e4ea9 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -1,4 +1,4 @@ -use std::fmt::{self, Write}; +use std::fmt::{self, Debug, Write}; use indexmap::IndexMap; @@ -13,6 +13,7 @@ use crate::r#enum::Enum; use crate::r#impl::Impl; use crate::r#struct::Struct; use crate::r#trait::Trait; +use crate::type_alias::TypeAlias; /// Defines a scope. /// @@ -219,6 +220,22 @@ impl Scope { self } + /// Push a new `TypeAlias`, returning a mutable reference to it. + pub fn new_type_alias(&mut self, name: &str, target: &str) -> &mut TypeAlias { + self.push_type_alias(TypeAlias::new(name, target)); + + match *self.items.last_mut().unwrap() { + Item::TypeAlias(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Push an `TypeAlias`. + pub fn push_type_alias(&mut self, item: TypeAlias) -> &mut Self { + self.items.push(Item::TypeAlias(item)); + self + } + /// Return a string representation of the scope. pub fn to_string(&self) -> String { let mut ret = String::new(); @@ -256,6 +273,7 @@ impl Scope { Item::Raw(ref v) => { write!(fmt, "{}\n", v)?; } + Item::TypeAlias(ref v) => v.fmt(fmt)?, } } diff --git a/src/type_alias.rs b/src/type_alias.rs new file mode 100644 index 0000000..574cb3c --- /dev/null +++ b/src/type_alias.rs @@ -0,0 +1,87 @@ +use core::fmt; +use std::fmt::Write; + +use crate::{type_def::TypeDef, Formatter, Type}; + +/// https://rust-lang.github.io/chalk/book/types/rust_types/alias.html#alias-types +#[derive(Debug, Clone)] +pub struct TypeAlias { + type_def: TypeDef, + ty: Type, +} + +impl TypeAlias { + pub fn new(name: &str, ty: &str) -> Self { + Self { + type_def: TypeDef::new(name), + ty: Type::new(ty), + } + } + pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + self.type_def.fmt_head("type", &[], fmt)?; + write!(fmt, " = ")?; + self.ty.fmt(fmt)?; + write!(fmt, ";")?; + Ok(()) + } + + /// Returns a reference to the type + pub fn type_def(&self) -> &Type { + &self.type_def.ty + } + + /// Set the TypeAliasure visibility. + pub fn vis(&mut self, vis: &str) -> &mut Self { + self.type_def.vis(vis); + self + } + + /// Add a generic to the TypeAlias. + pub fn generic(&mut self, name: &str) -> &mut Self { + self.type_def.ty.generic(name); + self + } + + /// Add a `where` bound to the TypeAlias. + pub fn bound(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.type_def.bound(name, ty); + self + } + + /// Set the TypeAliasure documentation. + pub fn doc(&mut self, docs: &str) -> &mut Self { + self.type_def.doc(docs); + self + } + + /// Add a new type that the TypeAlias should derive. + pub fn derive(&mut self, name: &str) -> &mut Self { + self.type_def.derive(name); + self + } + + /// Specify lint attribute to supress a warning or error. + pub fn allow(&mut self, allow: &str) -> &mut Self { + self.type_def.allow(allow); + self + } + + /// Specify representation. + pub fn repr(&mut self, repr: &str) -> &mut Self { + self.type_def.repr(repr); + self + } + + /// Set the type alias's ty. + pub fn set_ty(&mut self, ty: Type) { + self.ty = ty; + } + + /// Get a reference to the type alias's ty. + pub fn ty(&self) -> &Type { + &self.ty + } +} diff --git a/tests/codegen.rs b/tests/codegen.rs index 77e7346..07fddf8 100644 --- a/tests/codegen.rs +++ b/tests/codegen.rs @@ -24,6 +24,19 @@ struct Foo { assert_eq!(scope.to_string(), &expect[1..]); } +#[test] +fn type_alias() { + let mut scope = Scope::new(); + + scope + .new_type_alias("hello", "world").vis("pub"); + + let expect = r#" +pub type hello = world;"#; + + assert_eq!(scope.to_string(), &expect[1..]); +} + #[test] fn struct_with_pushed_field() {