mirror of
https://github.com/SpaceManiac/SpacemanDMM.git
synced 2025-12-23 05:36:47 +00:00
Reorganize ast.rs
This commit is contained in:
parent
e4c8a23605
commit
7340015fca
1 changed files with 414 additions and 395 deletions
|
|
@ -10,25 +10,8 @@ use ahash::RandomState;
|
|||
|
||||
use crate::error::Location;
|
||||
|
||||
#[derive(Copy, Clone, Eq, Debug)]
|
||||
pub struct Spanned<T> {
|
||||
// TODO: add a Span type and use it here
|
||||
pub location: Location,
|
||||
pub elem: T,
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for Spanned<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// Skips the location: allows easy recursive Eq checks
|
||||
self.elem == other.elem
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Spanned<T> {
|
||||
pub fn new(location: Location, elem: T) -> Spanned<T> {
|
||||
Spanned { location, elem }
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// Simple enums
|
||||
|
||||
/// The unary operators, both prefix and postfix.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
|
|
@ -46,6 +29,27 @@ impl UnaryOp {
|
|||
/// Prepare to display this unary operator around (to the left or right of)
|
||||
/// its operand.
|
||||
pub fn around<'a, T: fmt::Display + ?Sized>(self, expr: &'a T) -> impl fmt::Display + 'a {
|
||||
/// A formatting wrapper created by `UnaryOp::around`.
|
||||
struct Around<'a, T: 'a + ?Sized> {
|
||||
op: UnaryOp,
|
||||
expr: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T: fmt::Display + ?Sized> fmt::Display for Around<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::UnaryOp::*;
|
||||
match self.op {
|
||||
Neg => write!(f, "-{}", self.expr),
|
||||
Not => write!(f, "!{}", self.expr),
|
||||
BitNot => write!(f, "~{}", self.expr),
|
||||
PreIncr => write!(f, "++{}", self.expr),
|
||||
PostIncr => write!(f, "{}++", self.expr),
|
||||
PreDecr => write!(f, "--{}", self.expr),
|
||||
PostDecr => write!(f, "{}--", self.expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Around { op: self, expr }
|
||||
}
|
||||
|
||||
|
|
@ -62,75 +66,6 @@ impl UnaryOp {
|
|||
}
|
||||
}
|
||||
|
||||
/// A formatting wrapper created by `UnaryOp::around`.
|
||||
struct Around<'a, T: 'a + ?Sized> {
|
||||
op: UnaryOp,
|
||||
expr: &'a T,
|
||||
}
|
||||
|
||||
impl<'a, T: fmt::Display + ?Sized> fmt::Display for Around<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::UnaryOp::*;
|
||||
match self.op {
|
||||
Neg => write!(f, "-{}", self.expr),
|
||||
Not => write!(f, "!{}", self.expr),
|
||||
BitNot => write!(f, "~{}", self.expr),
|
||||
PreIncr => write!(f, "++{}", self.expr),
|
||||
PostIncr => write!(f, "{}++", self.expr),
|
||||
PreDecr => write!(f, "--{}", self.expr),
|
||||
PostDecr => write!(f, "{}--", self.expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Original `Ident` is an alias for `String`.
|
||||
pub type Ident = String;
|
||||
|
||||
// Ident2 is an opaque type which promises a limited interface.
|
||||
// It's a `Box<str>` for now (smaller than `Ident` by 8 bytes),
|
||||
// but could be replaced by interning later.
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct Ident2 {
|
||||
inner: Box<str>,
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Ident2 {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
&*self.inner == other
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Ident2 {
|
||||
fn from(v: &'a str) -> Self {
|
||||
Ident2 { inner: v.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Ident2 {
|
||||
fn from(v: String) -> Self {
|
||||
Ident2 { inner: v.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Ident2 {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &str {
|
||||
&*self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Ident2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Ident2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// The DM path operators.
|
||||
///
|
||||
/// Which path operator is used typically only matters at the start of a path.
|
||||
|
|
@ -160,34 +95,6 @@ impl fmt::Display for PathOp {
|
|||
}
|
||||
}
|
||||
|
||||
/// A (typically absolute) tree path where the path operator is irrelevant.
|
||||
pub type TreePath = Box<[Ident]>;
|
||||
|
||||
pub struct FormatTreePath<'a, T>(pub &'a [T]);
|
||||
|
||||
impl<'a, T: fmt::Display> fmt::Display for FormatTreePath<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for each in self.0.iter() {
|
||||
write!(f, "/{}", each)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A series of identifiers separated by path operators.
|
||||
pub type TypePath = Vec<(PathOp, Ident)>;
|
||||
|
||||
pub struct FormatTypePath<'a>(pub &'a [(PathOp, Ident)]);
|
||||
|
||||
impl<'a> fmt::Display for FormatTypePath<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for each in self.0.iter() {
|
||||
write!(f, "{}{}", each.0, each.1)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The binary operators.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum BinaryOp {
|
||||
|
|
@ -288,12 +195,6 @@ impl fmt::Display for AssignOp {
|
|||
}
|
||||
}
|
||||
|
||||
/// The ternary operator, represented uniformly for convenience.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum TernaryOp {
|
||||
Conditional,
|
||||
}
|
||||
|
||||
macro_rules! augmented {
|
||||
($($bin:ident = $aug:ident;)*) => {
|
||||
impl BinaryOp {
|
||||
|
|
@ -329,6 +230,391 @@ augmented! {
|
|||
RShift = RShiftAssign;
|
||||
}
|
||||
|
||||
/// The ternary operator, represented uniformly for convenience.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum TernaryOp {
|
||||
Conditional,
|
||||
}
|
||||
|
||||
/// The possible kinds of access operators for lists
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum ListAccessKind {
|
||||
/// `[]`
|
||||
Normal,
|
||||
/// `?[]`
|
||||
Safe,
|
||||
}
|
||||
|
||||
/// The possible kinds of index operators, for both fields and methods.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum PropertyAccessKind {
|
||||
/// `a.b`
|
||||
Dot,
|
||||
/// `a:b`
|
||||
Colon,
|
||||
/// `a?.b`
|
||||
SafeDot,
|
||||
/// `a?:b`
|
||||
SafeColon,
|
||||
}
|
||||
|
||||
impl PropertyAccessKind {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
PropertyAccessKind::Dot => ".",
|
||||
PropertyAccessKind::Colon => ":",
|
||||
PropertyAccessKind::SafeDot => "?.",
|
||||
PropertyAccessKind::SafeColon => "?:",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PropertyAccessKind {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
/// The proc declaration kind, either `proc` or `verb`.
|
||||
///
|
||||
/// DM requires referencing proc paths to include whether the target is
|
||||
/// declared as a proc or verb, even though the two modes are functionally
|
||||
/// identical in many other respects.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
|
||||
pub enum ProcDeclKind {
|
||||
Proc,
|
||||
Verb,
|
||||
}
|
||||
|
||||
impl ProcDeclKind {
|
||||
/// Attempt to convert a string to a declaration kind.
|
||||
pub fn from_name(name: &str) -> Option<ProcDeclKind> {
|
||||
match name {
|
||||
"proc" => Some(ProcDeclKind::Proc),
|
||||
"verb" => Some(ProcDeclKind::Verb),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether `self` is `ProcDeclKind::Verb`.
|
||||
pub fn is_verb(self) -> bool {
|
||||
self == ProcDeclKind::Verb
|
||||
}
|
||||
|
||||
/// Return the string representation of this declaration kind.
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
ProcDeclKind::Proc => "proc",
|
||||
ProcDeclKind::Verb => "verb",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ProcDeclKind {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum SettingMode {
|
||||
/// As in `set name = "Use"`.
|
||||
Assign,
|
||||
/// As in `set src in usr`.
|
||||
In,
|
||||
}
|
||||
|
||||
impl SettingMode {
|
||||
/// Return the string representation of this setting mode.
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
SettingMode::Assign => "=",
|
||||
SettingMode::In => "in",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SettingMode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Bitflags
|
||||
|
||||
macro_rules! type_table {
|
||||
($(#[$attr:meta])* pub struct $name:ident; $($txt:expr, $i:ident, $val:expr;)*) => {
|
||||
bitflags! {
|
||||
$(#[$attr])*
|
||||
/// A type specifier for verb arguments and input() calls.
|
||||
pub struct $name: u32 {
|
||||
$(const $i = $val;)*
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
pub fn from_str(text: &str) -> Option<Self> {
|
||||
match text {
|
||||
$(
|
||||
$txt => Some($name::$i),
|
||||
)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for $name {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut first = true;
|
||||
$(
|
||||
if self.contains($name::$i) {
|
||||
write!(fmt, "{}{}", if first { "" } else { "|" }, $txt)?;
|
||||
first = false;
|
||||
}
|
||||
)*
|
||||
if first {
|
||||
fmt.write_str("()")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_table! {
|
||||
/// A type specifier for verb arguments and input() calls.
|
||||
pub struct InputType;
|
||||
|
||||
// These values can be known with an invocation such as:
|
||||
// src << as(command_text)
|
||||
"mob", MOB, 1 << 0;
|
||||
"obj", OBJ, 1 << 1;
|
||||
"text", TEXT, 1 << 2;
|
||||
"num", NUM, 1 << 3;
|
||||
"file", FILE, 1 << 4;
|
||||
"turf", TURF, 1 << 5;
|
||||
"key", KEY, 1 << 6;
|
||||
"null", NULL, 1 << 7;
|
||||
"area", AREA, 1 << 8;
|
||||
"icon", ICON, 1 << 9;
|
||||
"sound", SOUND, 1 << 10;
|
||||
"message", MESSAGE, 1 << 11;
|
||||
"anything", ANYTHING, 1 << 12;
|
||||
"password", PASSWORD, 1 << 15;
|
||||
"command_text", COMMAND_TEXT, 1 << 16;
|
||||
"color", COLOR, 1 << 17;
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct VarTypeFlags: u8 {
|
||||
// DM flags
|
||||
const STATIC = 1 << 0;
|
||||
const CONST = 1 << 2;
|
||||
const TMP = 1 << 3;
|
||||
// SpacemanDMM flags
|
||||
const FINAL = 1 << 4;
|
||||
const PRIVATE = 1 << 5;
|
||||
const PROTECTED = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
impl VarTypeFlags {
|
||||
pub fn from_name(name: &str) -> Option<VarTypeFlags> {
|
||||
match name {
|
||||
// DM flags
|
||||
"global" | "static" => Some(VarTypeFlags::STATIC),
|
||||
"const" => Some(VarTypeFlags::CONST),
|
||||
"tmp" => Some(VarTypeFlags::TMP),
|
||||
// SpacemanDMM flags
|
||||
"SpacemanDMM_final" => Some(VarTypeFlags::FINAL),
|
||||
"SpacemanDMM_private" => Some(VarTypeFlags::PRIVATE),
|
||||
"SpacemanDMM_protected" => Some(VarTypeFlags::PROTECTED),
|
||||
// Fallback
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_static(&self) -> bool {
|
||||
self.contains(VarTypeFlags::STATIC)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_const(&self) -> bool {
|
||||
self.contains(VarTypeFlags::CONST)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_tmp(&self) -> bool {
|
||||
self.contains(VarTypeFlags::TMP)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_final(&self) -> bool {
|
||||
self.contains(VarTypeFlags::FINAL)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_private(&self) -> bool {
|
||||
self.contains(VarTypeFlags::PRIVATE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_protected(&self) -> bool {
|
||||
self.contains(VarTypeFlags::PROTECTED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_const_evaluable(&self) -> bool {
|
||||
self.contains(VarTypeFlags::CONST) || !self.intersects(VarTypeFlags::STATIC | VarTypeFlags::PROTECTED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_normal(&self) -> bool {
|
||||
!self.intersects(VarTypeFlags::CONST | VarTypeFlags::STATIC | VarTypeFlags::PROTECTED)
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<&'static str> {
|
||||
let mut v = Vec::new();
|
||||
if self.is_static() { v.push("static"); }
|
||||
if self.is_const() { v.push("const"); }
|
||||
if self.is_tmp() { v.push("tmp"); }
|
||||
if self.is_final() { v.push("SpacemanDMM_final"); }
|
||||
if self.is_private() { v.push("SpacemanDMM_private"); }
|
||||
if self.is_protected() { v.push("SpacemanDMM_protected"); }
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VarTypeFlags {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.is_static() {
|
||||
fmt.write_str("static/")?;
|
||||
}
|
||||
if self.is_const() {
|
||||
fmt.write_str("const/")?;
|
||||
}
|
||||
if self.is_tmp() {
|
||||
fmt.write_str("tmp/")?;
|
||||
}
|
||||
if self.is_final() {
|
||||
fmt.write_str("SpacemanDMM_final/")?;
|
||||
}
|
||||
if self.is_private() {
|
||||
fmt.write_str("SpacemanDMM_private/")?;
|
||||
}
|
||||
if self.is_protected() {
|
||||
fmt.write_str("SpacemanDMM_protected/")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helper types
|
||||
|
||||
// Original `Ident` is an alias for `String`.
|
||||
pub type Ident = String;
|
||||
|
||||
// Ident2 is an opaque type which promises a limited interface.
|
||||
// It's a `Box<str>` for now (smaller than `Ident` by 8 bytes),
|
||||
// but could be replaced by interning later.
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct Ident2 {
|
||||
inner: Box<str>,
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Ident2 {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
&*self.inner == other
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Ident2 {
|
||||
fn from(v: &'a str) -> Self {
|
||||
Ident2 { inner: v.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Ident2 {
|
||||
fn from(v: String) -> Self {
|
||||
Ident2 { inner: v.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Ident2 {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &str {
|
||||
&*self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Ident2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Ident2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// An AST element with an additional location attached.
|
||||
#[derive(Copy, Clone, Eq, Debug)]
|
||||
pub struct Spanned<T> {
|
||||
// TODO: add a Span type and use it here
|
||||
pub location: Location,
|
||||
pub elem: T,
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for Spanned<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// Skips the location: allows easy recursive Eq checks
|
||||
self.elem == other.elem
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Spanned<T> {
|
||||
pub fn new(location: Location, elem: T) -> Spanned<T> {
|
||||
Spanned { location, elem }
|
||||
}
|
||||
}
|
||||
|
||||
/// A (typically absolute) tree path where the path operator is irrelevant.
|
||||
pub type TreePath = Box<[Ident]>;
|
||||
|
||||
pub struct FormatTreePath<'a, T>(pub &'a [T]);
|
||||
|
||||
impl<'a, T: fmt::Display> fmt::Display for FormatTreePath<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for each in self.0.iter() {
|
||||
write!(f, "/{}", each)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A series of identifiers separated by path operators.
|
||||
pub type TypePath = Vec<(PathOp, Ident)>;
|
||||
|
||||
pub struct FormatTypePath<'a>(pub &'a [(PathOp, Ident)]);
|
||||
|
||||
impl<'a> fmt::Display for FormatTypePath<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for each in self.0.iter() {
|
||||
write!(f, "{}{}", each.0, each.1)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Terms and Expressions
|
||||
|
||||
/// A typepath optionally followed by a set of variables.
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Prefab {
|
||||
|
|
@ -688,45 +974,6 @@ impl From<Expression> for Term {
|
|||
}
|
||||
}
|
||||
|
||||
/// The possible kinds of access operators for lists
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum ListAccessKind {
|
||||
/// `[]`
|
||||
Normal,
|
||||
/// `?[]`
|
||||
Safe,
|
||||
}
|
||||
|
||||
/// The possible kinds of index operators, for both fields and methods.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum PropertyAccessKind {
|
||||
/// `a.b`
|
||||
Dot,
|
||||
/// `a:b`
|
||||
Colon,
|
||||
/// `a?.b`
|
||||
SafeDot,
|
||||
/// `a?:b`
|
||||
SafeColon,
|
||||
}
|
||||
|
||||
impl PropertyAccessKind {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
PropertyAccessKind::Dot => ".",
|
||||
PropertyAccessKind::Colon => ":",
|
||||
PropertyAccessKind::SafeDot => "?.",
|
||||
PropertyAccessKind::SafeColon => "?:",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PropertyAccessKind {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
/// An expression part which is applied to a term or another follow.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Follow {
|
||||
|
|
@ -751,47 +998,6 @@ impl From<Field> for Follow {
|
|||
}
|
||||
}
|
||||
|
||||
/// The proc declaration kind, either `proc` or `verb`.
|
||||
///
|
||||
/// DM requires referencing proc paths to include whether the target is
|
||||
/// declared as a proc or verb, even though the two modes are functionally
|
||||
/// identical in many other respects.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
|
||||
pub enum ProcDeclKind {
|
||||
Proc,
|
||||
Verb,
|
||||
}
|
||||
|
||||
impl ProcDeclKind {
|
||||
/// Attempt to convert a string to a declaration kind.
|
||||
pub fn from_name(name: &str) -> Option<ProcDeclKind> {
|
||||
match name {
|
||||
"proc" => Some(ProcDeclKind::Proc),
|
||||
"verb" => Some(ProcDeclKind::Verb),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether `self` is `ProcDeclKind::Verb`.
|
||||
pub fn is_verb(self) -> bool {
|
||||
self == ProcDeclKind::Verb
|
||||
}
|
||||
|
||||
/// Return the string representation of this declaration kind.
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
ProcDeclKind::Proc => "proc",
|
||||
ProcDeclKind::Verb => "verb",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ProcDeclKind {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
/// A parameter declaration in the header of a proc.
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct Parameter {
|
||||
|
|
@ -813,175 +1019,6 @@ impl fmt::Display for Parameter {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! type_table {
|
||||
($(#[$attr:meta])* pub struct $name:ident; $($txt:expr, $i:ident, $val:expr;)*) => {
|
||||
bitflags! {
|
||||
$(#[$attr])*
|
||||
/// A type specifier for verb arguments and input() calls.
|
||||
pub struct $name: u32 {
|
||||
$(const $i = $val;)*
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
pub fn from_str(text: &str) -> Option<Self> {
|
||||
match text {
|
||||
$(
|
||||
$txt => Some($name::$i),
|
||||
)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for $name {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut first = true;
|
||||
$(
|
||||
if self.contains($name::$i) {
|
||||
write!(fmt, "{}{}", if first { "" } else { "|" }, $txt)?;
|
||||
first = false;
|
||||
}
|
||||
)*
|
||||
if first {
|
||||
fmt.write_str("()")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_table! {
|
||||
/// A type specifier for verb arguments and input() calls.
|
||||
pub struct InputType;
|
||||
|
||||
// These values can be known with an invocation such as:
|
||||
// src << as(command_text)
|
||||
"mob", MOB, 1 << 0;
|
||||
"obj", OBJ, 1 << 1;
|
||||
"text", TEXT, 1 << 2;
|
||||
"num", NUM, 1 << 3;
|
||||
"file", FILE, 1 << 4;
|
||||
"turf", TURF, 1 << 5;
|
||||
"key", KEY, 1 << 6;
|
||||
"null", NULL, 1 << 7;
|
||||
"area", AREA, 1 << 8;
|
||||
"icon", ICON, 1 << 9;
|
||||
"sound", SOUND, 1 << 10;
|
||||
"message", MESSAGE, 1 << 11;
|
||||
"anything", ANYTHING, 1 << 12;
|
||||
"password", PASSWORD, 1 << 15;
|
||||
"command_text", COMMAND_TEXT, 1 << 16;
|
||||
"color", COLOR, 1 << 17;
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct VarTypeFlags: u8 {
|
||||
// DM flags
|
||||
const STATIC = 1 << 0;
|
||||
const CONST = 1 << 2;
|
||||
const TMP = 1 << 3;
|
||||
// SpacemanDMM flags
|
||||
const FINAL = 1 << 4;
|
||||
const PRIVATE = 1 << 5;
|
||||
const PROTECTED = 1 << 6;
|
||||
}
|
||||
}
|
||||
|
||||
impl VarTypeFlags {
|
||||
pub fn from_name(name: &str) -> Option<VarTypeFlags> {
|
||||
match name {
|
||||
// DM flags
|
||||
"global" | "static" => Some(VarTypeFlags::STATIC),
|
||||
"const" => Some(VarTypeFlags::CONST),
|
||||
"tmp" => Some(VarTypeFlags::TMP),
|
||||
// SpacemanDMM flags
|
||||
"SpacemanDMM_final" => Some(VarTypeFlags::FINAL),
|
||||
"SpacemanDMM_private" => Some(VarTypeFlags::PRIVATE),
|
||||
"SpacemanDMM_protected" => Some(VarTypeFlags::PROTECTED),
|
||||
// Fallback
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_static(&self) -> bool {
|
||||
self.contains(VarTypeFlags::STATIC)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_const(&self) -> bool {
|
||||
self.contains(VarTypeFlags::CONST)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_tmp(&self) -> bool {
|
||||
self.contains(VarTypeFlags::TMP)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_final(&self) -> bool {
|
||||
self.contains(VarTypeFlags::FINAL)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_private(&self) -> bool {
|
||||
self.contains(VarTypeFlags::PRIVATE)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_protected(&self) -> bool {
|
||||
self.contains(VarTypeFlags::PROTECTED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_const_evaluable(&self) -> bool {
|
||||
self.contains(VarTypeFlags::CONST) || !self.intersects(VarTypeFlags::STATIC | VarTypeFlags::PROTECTED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_normal(&self) -> bool {
|
||||
!self.intersects(VarTypeFlags::CONST | VarTypeFlags::STATIC | VarTypeFlags::PROTECTED)
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<&'static str> {
|
||||
let mut v = Vec::new();
|
||||
if self.is_static() { v.push("static"); }
|
||||
if self.is_const() { v.push("const"); }
|
||||
if self.is_tmp() { v.push("tmp"); }
|
||||
if self.is_final() { v.push("SpacemanDMM_final"); }
|
||||
if self.is_private() { v.push("SpacemanDMM_private"); }
|
||||
if self.is_protected() { v.push("SpacemanDMM_protected"); }
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VarTypeFlags {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.is_static() {
|
||||
fmt.write_str("static/")?;
|
||||
}
|
||||
if self.is_const() {
|
||||
fmt.write_str("const/")?;
|
||||
}
|
||||
if self.is_tmp() {
|
||||
fmt.write_str("tmp/")?;
|
||||
}
|
||||
if self.is_final() {
|
||||
fmt.write_str("SpacemanDMM_final/")?;
|
||||
}
|
||||
if self.is_private() {
|
||||
fmt.write_str("SpacemanDMM_private/")?;
|
||||
}
|
||||
if self.is_protected() {
|
||||
fmt.write_str("SpacemanDMM_protected/")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A type which may be ascribed to a `var`.
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct VarType {
|
||||
|
|
@ -1088,6 +1125,9 @@ impl VarSuffix {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Statements
|
||||
|
||||
/// A block of statements.
|
||||
pub type Block = Box<[Spanned<Statement>]>;
|
||||
|
||||
|
|
@ -1174,36 +1214,15 @@ pub struct VarStatement {
|
|||
pub value: Option<Expression>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum SettingMode {
|
||||
/// As in `set name = "Use"`.
|
||||
Assign,
|
||||
/// As in `set src in usr`.
|
||||
In,
|
||||
}
|
||||
|
||||
impl SettingMode {
|
||||
/// Return the string representation of this setting mode.
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
SettingMode::Assign => "=",
|
||||
SettingMode::In => "in",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SettingMode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(self.name())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Case {
|
||||
Exact(Expression),
|
||||
Range(Expression, Expression),
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Miscellaneous
|
||||
|
||||
pub const KNOWN_SETTING_NAMES: &[&str] = &[
|
||||
"name",
|
||||
"desc",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue