From a40b7da1ab4028bba53f9768b7a58a7c619a052d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Mon, 18 May 2026 20:34:43 +0200 Subject: Concatenation operator for lists Changelog: Added `++` operator to concatenate lists --- README.md | 6 +++++- src/Parser/Expr.hs | 24 ++++++++++++++++++++++++ test/asset/list/concat.et | 8 ++++++++ test/script/list.et | 8 ++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d40a6f..62ae1a0 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,11 @@ let numbers = [1, 2, 4] List elements can be of any type, but all elements of a particular list must have the same type. They can be concatenated using the `concat` function, which takes a list of lists as argument: ``` -let list = concat [[1], [2, 3], [4]] # = [1, 2, 3, 4,] +let list = concat [[1], [2, 3], [4]] # = [1, 2, 3, 4] +``` +Or with the `++` operator: +``` +let list = [1] ++ [2, 3] ++ [4] # = [1, 2, 3, 4] ``` ### Built-in commands diff --git a/src/Parser/Expr.hs b/src/Parser/Expr.hs index 7d57791..a0ae70d 100644 --- a/src/Parser/Expr.hs +++ b/src/Parser/Expr.hs @@ -302,6 +302,19 @@ someExpr complexity = label "expression" $ do , SomeBinOp ((-) @Scientific) ] ] + , [ let tvar = TypeVar "a" + targs = FunctionArguments $ M.fromList + [ ( Just "$l", ( VarName "$l", SomeArgumentType RequiredArgument $ ExprTypeApp (ExprTypeConstr1 (Proxy @[])) [ ExprTypeVar tvar ]) ) + , ( Just "$r", ( VarName "$r", SomeArgumentType RequiredArgument $ ExprTypeApp (ExprTypeConstr1 (Proxy @[])) [ ExprTypeVar tvar ]) ) + ] + in infixrExpr "++" $ SomeExpr $ TypeLambda tvar (ExprTypeFunction (ExprTypeArguments $ fmap snd targs) (ExprTypeApp (ExprTypeConstr1 (Proxy @[])) [ ExprTypeVar tvar ])) $ \case + ExprTypePrim (Proxy :: Proxy a) -> + HideFunType (fmap snd targs) $ ArgsReq targs $ + FunctionAbstraction $ ((++) @a) + <$> (Variable SourceLineBuiltin $ LocalVarName $ VarName "$l") + <*> (Variable SourceLineBuiltin $ LocalVarName $ VarName "$r") + t -> Undefined ("ambiguous type ‘" <> T.unpack (textSomeExprType t) <> "’ for operator ‘++’") :: Expr DynamicType + ] , [ binary' "==" (\op xs ys -> length xs == length ys && and (zipWith op xs ys)) $ [ SomeBinOp ((==) @Integer) , SomeBinOp ((==) @Scientific) @@ -345,6 +358,17 @@ someExpr complexity = label "expression" $ do choice $ map (\(SomeUnOp op) -> SomeExpr <$> applyUnOp off op e) ops + infixrExpr :: String -> SomeExpr -> Operator TestParser (TestParser SomeExpr) + infixrExpr name fun = InfixR $ do + void $ osymbol name + return $ \p q -> do + loff <- stateOffset <$> getParserState + l <- p + roff <- stateOffset <$> getParserState + r <- q + applyFunctionArguments (FunctionArguments $ M.fromList [ ( Just "$l", ( loff, l ) ), ( Just "$r", ( roff, r ) ) ]) fun + + binary :: String -> [SomeBinOp] -> Operator TestParser (TestParser SomeExpr) binary name = binary' name (undefined :: forall a b. (a -> b -> Void) -> [a] -> [b] -> Integer) -- use 'Void' that can never match actually used type to disable recursion diff --git a/test/asset/list/concat.et b/test/asset/list/concat.et index 613df57..c669a78 100644 --- a/test/asset/list/concat.et +++ b/test/asset/list/concat.et @@ -28,3 +28,11 @@ test Test: local: shell on n: echo "c3-end" + + let c4 = list1 ++ list2 ++ [ 6, 5 ] ++ list2 + for i in c4: + shell on n: + echo "c4 $i" + local: + shell on n: + echo "c4-end" diff --git a/test/script/list.et b/test/script/list.et index a654111..cfd4803 100644 --- a/test/script/list.et +++ b/test/script/list.et @@ -28,6 +28,14 @@ test ListConcat: "c3 2" "c3 3" "c3-end" + "c4 1" + "c4 2" + "c4 3" + "c4 6" + "c4 5" + "c4 2" + "c4 3" + "c4-end" local: expect /(run-.*)/ capture done guard (done == "run-done") -- cgit v1.2.3