Feat: lots of convenience stuff

This commit is contained in:
2026-02-24 00:52:40 +01:00
parent 8f131b46cc
commit 848d0e773f
15 changed files with 440 additions and 26 deletions

View File

@@ -143,6 +143,19 @@ fn compile(tokens: &[Token], dict: &Dictionary) -> Result<Vec<Op>, String> {
ops.push(Op::Quotation(Arc::from(quote_ops), Some(body_span)));
} else if word == "}" {
return Err("unexpected }".into());
} else if word == "[" {
let (bracket_ops, consumed, end_span) =
compile_bracket(&tokens[i + 1..], dict)?;
i += consumed;
ops.push(Op::Mark);
ops.extend(bracket_ops);
let count_span = SourceSpan {
start: span.start,
end: end_span.end,
};
ops.push(Op::Count(Some(count_span)));
} else if word == "]" {
return Err("unexpected ]".into());
} else if word == ":" {
let (consumed, name, body) = compile_colon_def(&tokens[i + 1..], dict)?;
i += consumed;
@@ -211,6 +224,38 @@ fn compile_quotation(
Ok((quote_ops, end_idx + 1, end_span))
}
fn compile_bracket(
tokens: &[Token],
dict: &Dictionary,
) -> Result<(Vec<Op>, usize, SourceSpan), String> {
let mut depth = 1;
let mut end_idx = None;
for (i, tok) in tokens.iter().enumerate() {
if let Token::Word(w, _) = tok {
match w.as_str() {
"[" => depth += 1,
"]" => {
depth -= 1;
if depth == 0 {
end_idx = Some(i);
break;
}
}
_ => {}
}
}
}
let end_idx = end_idx.ok_or("missing ]")?;
let end_span = match &tokens[end_idx] {
Token::Word(_, span) => *span,
_ => unreachable!(),
};
let body_ops = compile(&tokens[..end_idx], dict)?;
Ok((body_ops, end_idx + 1, end_span))
}
fn token_span(tok: &Token) -> Option<SourceSpan> {
match tok {
Token::Int(_, s) | Token::Float(_, s) | Token::Str(_, s) | Token::Word(_, s) => Some(*s),