Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement around as a complement to over #560

Merged
merged 9 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions site/primitives.json
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,15 @@
"description": "Invert the behavior of a function, but keep its signature",
"experimental": true
},
"around": {
"ascii": "'",
"glyph": "’",
"args": 2,
"outputs": 3,
"class": "Stack",
"description": "Duplicate the top of the stack around the second element",
"experimental": true
},
"assert": {
"glyph": "⍤",
"args": 2,
Expand Down
16 changes: 0 additions & 16 deletions site/src/editor/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,6 @@ pub fn gen_code_view(code: &str) -> View {
SpanKind::String => "string-literal-span",
SpanKind::Comment | SpanKind::OutputComment => "comment-span",
SpanKind::Strand => "strand-span",
SpanKind::StackSwizzle(sw) => sig_class(sw.signature()),
SpanKind::ArraySwizzle(sw) => sig_class(sw.signature()),
SpanKind::Subscript(None, _) => "number-literal",
SpanKind::Subscript(Some(prim), n) => {
prim_sig_class(*prim, prim.subscript_sig(*n))
Expand Down Expand Up @@ -570,20 +568,6 @@ pub fn gen_code_view(code: &str) -> View {
view!(<span class=class data-title=title>{text}</span>).into_view(),
)
}
SpanKind::StackSwizzle(sw) => {
let class = format!("code-span {}", color_class);
let title = format!("stack swizzle {}", sw.signature());
frag_views.push(
view!(<span class=class data-title=title>{text}</span>).into_view(),
)
}
SpanKind::ArraySwizzle(sw) => {
let class = format!("code-span {}", color_class);
let title = format!("array swizzle {}", sw.signature());
frag_views.push(
view!(<span class=class data-title=title>{text}</span>).into_view(),
)
}
SpanKind::Label => {
let label = text.trim_start_matches('$');
let mut components = [0f32; 3];
Expand Down
15 changes: 0 additions & 15 deletions src/algorithm/invert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,6 @@ static INVERT_PATTERNS: &[&dyn InvertPattern] = {
&InvertPatternFn(invert_split_pattern, "split"),
&InvertPatternFn(invert_rows_pattern, "rows"),
&InvertPatternFn(invert_dup_pattern, "dup"),
&InvertPatternFn(invert_stack_swizzle_pattern, "stack swizzle"),
&InvertPatternFn(invert_select_pattern, "select"),
&pat!(Sqrt, (Dup, Mul)),
&pat!((Dup, Add), (2, Div)),
Expand Down Expand Up @@ -1394,20 +1393,6 @@ fn under_dup_pattern<'a>(
Ok((input, (befores, afters)))
}

fn invert_stack_swizzle_pattern<'a>(
input: &'a [Instr],
_: &mut Compiler,
) -> InversionResult<(&'a [Instr], EcoVec<Instr>)> {
let [Instr::StackSwizzle(swizzle, span), input @ ..] = input else {
return generic();
};
let instrs = eco_vec![Instr::StackSwizzle(
swizzle.inverse().ok_or(Generic)?,
*span
)];
Ok((input, instrs))
}

fn invert_select_pattern<'a>(
input: &'a [Instr],
_: &mut Compiler,
Expand Down
134 changes: 132 additions & 2 deletions src/assembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use ecow::{eco_vec, EcoString, EcoVec};
use serde::*;

use crate::{
is_ident_char, CodeSpan, FuncSlice, Function, InputSrc, Instr, IntoInputSrc, LocalName, Module,
Signature, Span, Uiua, UiuaResult, Value,
is_ident_char, CodeSpan, DynamicFunction, FuncSlice, Function, Ident, ImplPrimitive, InputSrc,
Instr, IntoInputSrc, LocalName, Module, Primitive, Signature, Span, TempStack, Uiua,
UiuaResult, Value,
};

/// A compiled Uiua assembly
Expand Down Expand Up @@ -713,3 +714,132 @@ impl Inputs {
}
}
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
enum InstrRep {
#[serde(rename = "#")]
Comment(Ident),
CallGlobal(usize, bool, Signature),
BindGlobal(usize, usize),
BeginArray,
EndArray(bool, usize),
Call(usize),
CallRecursive(usize),
Recur(usize),
PushFunc(Function),
Switch(usize, Signature, usize, bool),
Format(EcoVec<EcoString>, usize),
MatchFormatPattern(EcoVec<EcoString>, usize),
Label(EcoString, usize, bool),
ValidateType(usize, EcoString, u8, usize),
Dynamic(DynamicFunction),
Unpack(usize, usize, bool),
TouchStack(usize, usize),
PushTemp(TempStack, usize, usize),
PopTemp(TempStack, usize, usize),
CopyToTemp(TempStack, usize, usize),
PushSig(Signature),
PopSig,
SetOutputComment(usize, usize),
#[serde(untagged)]
Push(Value),
#[serde(untagged)]
Prim(Primitive, usize),
#[serde(untagged)]
ImplPrim(ImplPrimitive, usize),
}

impl From<Instr> for InstrRep {
fn from(value: Instr) -> Self {
match value {
Instr::Comment(ident) => Self::Comment(ident),
Instr::Push(value) => Self::Push(value),
Instr::CallGlobal { index, call, sig } => Self::CallGlobal(index, call, sig),
Instr::BindGlobal { span, index } => Self::BindGlobal(span, index),
Instr::BeginArray => Self::BeginArray,
Instr::EndArray { boxed, span } => Self::EndArray(boxed, span),
Instr::Prim(prim, span) => Self::Prim(prim, span),
Instr::ImplPrim(prim, span) => Self::ImplPrim(prim, span),
Instr::Call(span) => Self::Call(span),
Instr::CallRecursive(span) => Self::CallRecursive(span),
Instr::Recur(span) => Self::Recur(span),
Instr::PushFunc(func) => Self::PushFunc(func),
Instr::Switch {
count,
sig,
span,
under_cond,
} => Self::Switch(count, sig, span, under_cond),
Instr::Format { parts, span } => Self::Format(parts, span),
Instr::MatchFormatPattern { parts, span } => Self::MatchFormatPattern(parts, span),
Instr::Label {
label,
span,
remove,
} => Self::Label(label, span, remove),
Instr::ValidateType {
index,
name,
type_num,
span,
} => Self::ValidateType(index, name, type_num, span),
Instr::Dynamic(func) => Self::Dynamic(func),
Instr::Unpack { count, span, unbox } => Self::Unpack(count, span, unbox),
Instr::TouchStack { count, span } => Self::TouchStack(count, span),
Instr::PushTemp { stack, count, span } => Self::PushTemp(stack, count, span),
Instr::PopTemp { stack, count, span } => Self::PopTemp(stack, count, span),
Instr::CopyToTemp { stack, count, span } => Self::CopyToTemp(stack, count, span),
Instr::PushSig(sig) => Self::PushSig(sig),
Instr::PopSig => Self::PopSig,
Instr::SetOutputComment { i, n } => Self::SetOutputComment(i, n),
}
}
}

impl From<InstrRep> for Instr {
fn from(value: InstrRep) -> Self {
match value {
InstrRep::Comment(ident) => Self::Comment(ident),
InstrRep::Push(value) => Self::Push(value),
InstrRep::CallGlobal(index, call, sig) => Self::CallGlobal { index, call, sig },
InstrRep::BindGlobal(span, index) => Self::BindGlobal { span, index },
InstrRep::BeginArray => Self::BeginArray,
InstrRep::EndArray(boxed, span) => Self::EndArray { boxed, span },
InstrRep::Prim(prim, span) => Self::Prim(prim, span),
InstrRep::ImplPrim(prim, span) => Self::ImplPrim(prim, span),
InstrRep::Call(span) => Self::Call(span),
InstrRep::CallRecursive(span) => Self::CallRecursive(span),
InstrRep::Recur(span) => Self::Recur(span),
InstrRep::PushFunc(func) => Self::PushFunc(func),
InstrRep::Switch(count, sig, span, under_cond) => Self::Switch {
count,
sig,
span,
under_cond,
},
InstrRep::Format(parts, span) => Self::Format { parts, span },
InstrRep::MatchFormatPattern(parts, span) => Self::MatchFormatPattern { parts, span },
InstrRep::Label(label, span, remove) => Self::Label {
label,
span,
remove,
},
InstrRep::ValidateType(index, name, type_num, span) => Self::ValidateType {
index,
name,
type_num,
span,
},
InstrRep::Dynamic(func) => Self::Dynamic(func),
InstrRep::Unpack(count, span, unbox) => Self::Unpack { count, span, unbox },
InstrRep::TouchStack(count, span) => Self::TouchStack { count, span },
InstrRep::PushTemp(stack, count, span) => Self::PushTemp { stack, count, span },
InstrRep::PopTemp(stack, count, span) => Self::PopTemp { stack, count, span },
InstrRep::CopyToTemp(stack, count, span) => Self::CopyToTemp { stack, count, span },
InstrRep::PushSig(sig) => Self::PushSig(sig),
InstrRep::PopSig => Self::PopSig,
InstrRep::SetOutputComment(i, n) => Self::SetOutputComment { i, n },
}
}
}
8 changes: 1 addition & 7 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
function::{FunctionId, Signature},
lex::{CodeSpan, Sp},
parse::ident_modifier_args,
ArraySwizzle, Ident, Primitive, SemanticComment, StackSwizzle, SUBSCRIPT_NUMS,
Ident, Primitive, SemanticComment, SUBSCRIPT_NUMS,
};

/// A top-level item
Expand Down Expand Up @@ -137,8 +137,6 @@ pub enum Word {
Primitive(Primitive),
Modified(Box<Modified>),
Placeholder(PlaceholderOp),
StackSwizzle(StackSwizzle),
ArraySwizzle(ArraySwizzle),
Comment(String),
Spaces,
BreakLine,
Expand Down Expand Up @@ -191,8 +189,6 @@ impl PartialEq for Word {
}
(Self::Placeholder(_), Self::Placeholder(_)) => false,
(Self::Comment(a), Self::Comment(b)) => a == b,
(Self::StackSwizzle(a), Self::StackSwizzle(b)) => a == b,
(Self::ArraySwizzle(a), Self::ArraySwizzle(b)) => a == b,
_ => discriminant(self) == discriminant(other),
}
}
Expand Down Expand Up @@ -266,8 +262,6 @@ impl fmt::Debug for Word {
Word::Spaces => write!(f, "' '"),
Word::Comment(comment) => write!(f, "# {comment}"),
Word::Placeholder(op) => write!(f, "{op}"),
Word::StackSwizzle(swizzle) => write!(f, "{swizzle}"),
Word::ArraySwizzle(swizzle) => write!(f, "{swizzle}"),
Word::BreakLine => write!(f, "break_line"),
Word::FlipLine => write!(f, "unbreak_line"),
Word::SemanticComment(comment) => write!(f, "{comment}"),
Expand Down
1 change: 0 additions & 1 deletion src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,6 @@ impl VirtualEnv {
Instr::MatchFormatPattern { parts, .. } => {
self.handle_args_outputs(1, parts.len().saturating_sub(1))?
}
Instr::StackSwizzle(sw, _) => self.handle_sig(sw.signature())?,
Instr::Dynamic(f) => self.handle_sig(f.signature)?,
Instr::Unpack { count, .. } => self.handle_args_outputs(1, *count)?,
Instr::TouchStack { count, .. } => self.handle_args_outputs(*count, *count)?,
Expand Down
117 changes: 0 additions & 117 deletions src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1425,8 +1425,6 @@ code:
Word::Placeholder(_) => {
// We could error here, but it's easier to handle it higher up
}
Word::StackSwizzle(sw) => self.stack_swizzle(sw, word.span, call),
Word::ArraySwizzle(sw) => self.array_swizzle(sw, word.span, call)?,
Word::SemanticComment(sc) => match sc {
SemanticComment::Experimental => self.scope.experimental = true,
SemanticComment::NoInline => {
Expand Down Expand Up @@ -2254,121 +2252,6 @@ code:
}
Ok(())
}
fn stack_swizzle(&mut self, swiz: StackSwizzle, span: CodeSpan, call: bool) {
self.experimental_error(&span, || {
"Swizzles are experimental. To use them, add \
`# Experimental!` to the top of the file."
});
self.emit_diagnostic(
"Stack swizzles are deprecated and will be removed in the future.",
DiagnosticKind::Warning,
span.clone(),
);
let sig = swiz.signature();
let spandex = self.add_span(span.clone());
let equivalent = match (swiz.indices.as_slice(), swiz.fix.as_slice()) {
([0], [false]) => Some(Primitive::Identity),
([0], [true]) => Some(Primitive::Fix),
([1, 0], [false, false]) => Some(Primitive::Flip),
([0, 0], [false, false]) => Some(Primitive::Dup),
([1, 0, 1], [false, false, false]) => Some(Primitive::Over),
_ => None,
};
let mut instr = if let Some(prim) = equivalent {
self.emit_diagnostic(
format!(
"This swizzle is equivalent to {}. \
Use that instead.",
prim.format()
),
DiagnosticKind::Style,
span.clone(),
);
Instr::Prim(prim, spandex)
} else {
Instr::StackSwizzle(swiz, spandex)
};
if !call {
instr = Instr::PushFunc(self.make_function(
FunctionId::Anonymous(span),
sig,
eco_vec![instr].into(),
));
}
self.push_instr(instr);
}
fn array_swizzle(&mut self, swiz: ArraySwizzle, span: CodeSpan, call: bool) -> UiuaResult {
if !self.scope.experimental {
self.add_error(
span.clone(),
"Swizzles are experimental. To use them, add \
`# Experimental!` to the top of the file.",
);
}
self.emit_diagnostic(
"Array swizzles are deprecated and will be removed in the future.",
DiagnosticKind::Warning,
span.clone(),
);
let sig = swiz.signature();
let mut instrs = EcoVec::new();
let normal_ordered = (swiz.indices.iter().enumerate()).all(|(i, &idx)| i == idx as usize);
let spandex = self.add_span(span.clone());
if normal_ordered {
let val = Value::from(swiz.indices.len());
instrs.extend([Instr::push(val), Instr::Prim(Primitive::Take, spandex)]);
} else {
let arr = Array::from_iter(swiz.indices.iter().map(|&i| i as f64));
instrs.extend([Instr::push(arr), Instr::Prim(Primitive::Select, spandex)]);
}
if swiz.unbox.iter().all(|&b| b) {
instrs.push(Instr::Unpack {
count: sig.outputs,
span: spandex,
unbox: true,
})
} else {
instrs.push(Instr::Unpack {
count: sig.outputs,
span: spandex,
unbox: false,
});
if !swiz.unbox.iter().all(|&b| !b) {
let mut boxed_indices: Vec<usize> = (swiz.unbox.iter().enumerate())
.filter_map(|(i, b)| b.then_some(i))
.collect();
let mut curr_index = boxed_indices.pop().unwrap();
if curr_index != 0 {
instrs.push(Instr::PushTemp {
stack: TempStack::Inline,
count: curr_index,
span: spandex,
});
}
instrs.push(Instr::ImplPrim(ImplPrimitive::UnBox, spandex));
for i in boxed_indices.into_iter().rev() {
let diff = curr_index - i;
instrs.extend([
Instr::pop_inline(diff, spandex),
Instr::ImplPrim(ImplPrimitive::UnBox, spandex),
]);
curr_index = i;
}
if curr_index != 0 {
instrs.push(Instr::pop_inline(curr_index, spandex));
}
}
}
if !call {
instrs = eco_vec![Instr::PushFunc(self.make_function(
FunctionId::Anonymous(span),
sig,
instrs.into(),
))];
}
self.push_all_instrs(instrs);
Ok(())
}
pub(crate) fn inlinable(&self, instrs: &[Instr], flags: FunctionFlags) -> bool {
use ImplPrimitive::*;
use Primitive::*;
Expand Down
Loading