Add array concat operator

This commit is contained in:
2026-06-19 01:01:04 +09:00
parent 6da0ec4c77
commit 01ad6dca52
17 changed files with 6365 additions and 5138 deletions
+1
View File
@@ -133,6 +133,7 @@ pub enum BinaryOp {
Sub,
Mul,
Div,
Concat,
Equal,
NotEqual,
Greater,
+44
View File
@@ -410,6 +410,7 @@ impl<L: SourceLoader> Engine<L> {
BinaryOp::Div => {
arithmetic(lhs_value, rhs_value, ArithmeticOp::Div, span)
}
BinaryOp::Concat => concat_arrays(lhs_value, rhs_value, span),
BinaryOp::Equal => {
compare_expr(lhs_value, rhs_value, CompareExprOp::Equal, span)
}
@@ -1208,6 +1209,23 @@ fn comparison_type_error(span: Span) -> Diagnostic {
)
}
fn concat_arrays(lhs: RuntimeValue, rhs: RuntimeValue, span: Span) -> Result<RuntimeValue> {
match (lhs, rhs) {
(
RuntimeValue::Concrete(ConcreteValue::Array(mut lhs)),
RuntimeValue::Concrete(ConcreteValue::Array(rhs)),
) => {
lhs.extend(rhs);
Ok(RuntimeValue::Concrete(ConcreteValue::Array(lhs)))
}
_ => Err(Diagnostic::new(
DiagnosticKind::TypeMismatch,
span,
"'++' expects array values",
)),
}
}
fn arithmetic(
lhs: RuntimeValue,
rhs: RuntimeValue,
@@ -1395,6 +1413,32 @@ mod tests {
assert!(engine.eval_root().is_err());
}
#[test]
fn evaluates_array_concat() {
let data = eval_data(
r#"
[1, 2] ++ [3, 4]
"#,
);
assert_eq!(
data,
Data::Array(vec![Data::Int(1), Data::Int(2), Data::Int(3), Data::Int(4)])
);
}
#[test]
fn array_concat_has_lower_precedence_than_arithmetic() {
let data = eval_data("[1 + 1] ++ [2 * 2]");
assert_eq!(data, Data::Array(vec![Data::Int(2), Data::Int(4)]));
}
#[test]
fn rejects_invalid_array_concat_operands() {
let parsed = parse_source("[1] ++ 2").unwrap();
let mut engine = Engine::from_parse(parsed.ast, parsed.root);
assert!(engine.eval_root().is_err());
}
#[test]
fn evaluates_logical_and_comparison_expressions() {
let data = eval_data(
+6 -1
View File
@@ -42,6 +42,7 @@ pub enum TokenKind {
AmpAmp,
PipePipe,
Plus,
PlusPlus,
Minus,
Star,
Slash,
@@ -166,7 +167,11 @@ impl<'a> Lexer<'a> {
}
b'+' => {
self.pos += 1;
TokenKind::Plus
if self.consume(b'+') {
TokenKind::PlusPlus
} else {
TokenKind::Plus
}
}
b'-' => {
self.pos += 1;
+10
View File
@@ -147,6 +147,14 @@ impl Parser {
},
span,
),
InfixKind::Concat => self.ast.push(
Expr::Binary {
op: BinaryOp::Concat,
lhs,
rhs,
},
span,
),
InfixKind::Equal => self.ast.push(
Expr::Binary {
op: BinaryOp::Equal,
@@ -532,6 +540,7 @@ impl Parser {
TokenKind::Gte => Some((InfixKind::GreaterEqual, 11, 12)),
TokenKind::Lt => Some((InfixKind::Less, 11, 12)),
TokenKind::Lte => Some((InfixKind::LessEqual, 11, 12)),
TokenKind::PlusPlus => Some((InfixKind::Concat, 12, 13)),
TokenKind::Plus => Some((InfixKind::Add, 13, 14)),
TokenKind::Minus => Some((InfixKind::Sub, 13, 14)),
TokenKind::Star => Some((InfixKind::Mul, 15, 16)),
@@ -632,6 +641,7 @@ enum InfixKind {
Sub,
Mul,
Div,
Concat,
Equal,
NotEqual,
Greater,