├── .clj-kondo └── config.edn ├── .cljfmt.edn ├── .gitattributes ├── .github └── Code-of-Conduct.md ├── .gitignore ├── .profile ├── .rc ├── .version.ys ├── .vscode └── settings.json ├── Changes ├── Contributing.md ├── License ├── Makefile ├── Meta ├── ReadMe.md ├── blog ├── 2023-12-01.md ├── 2023-12-02.md ├── 2023-12-03.md ├── 2023-12-04.md ├── 2023-12-05.md ├── 2023-12-06.md ├── 2023-12-07.md ├── 2023-12-08.md ├── 2023-12-09.md ├── 2023-12-10.md ├── 2023-12-11.md ├── 2023-12-12.md ├── 2023-12-13.md ├── 2023-12-14.md ├── 2023-12-15.md ├── 2023-12-16.md ├── 2023-12-17.md ├── 2023-12-18.md ├── 2023-12-19.md ├── 2023-12-20.md ├── 2023-12-21.md ├── 2023-12-22.md ├── 2023-12-23.md ├── 2023-12-24.md ├── 2024-03-14.md ├── 2024-04-16.md ├── 2024-06-20.md ├── 2024-07-17.md ├── 2024-11-05.md ├── 2024-11-29.md ├── 2025-03-10.md └── welcome.md ├── clojure ├── Makefile ├── deps.edn ├── project.clj ├── src │ └── yamlscript │ │ └── core.clj ├── test │ └── yamlscript │ │ └── main_test.clj └── util │ └── get-setting ├── common ├── base.mk ├── binding.mk ├── clojure.mk ├── install.mk ├── java.mk ├── native.mk ├── python.mk ├── readme.md ├── reflection.json ├── release.md ├── vars-cli.mk ├── vars-core.mk ├── vars-libys.mk ├── vars.mk └── zild.mk ├── core ├── License ├── Makefile ├── ReadMe.md ├── deps.edn ├── project.clj ├── resources │ └── _ ├── src │ ├── a0 │ │ └── patch_pprint.clj │ ├── yamlscript │ │ ├── ast.clj │ │ ├── builder.clj │ │ ├── cache.clj │ │ ├── common.clj │ │ ├── compiler.clj │ │ ├── composer.clj │ │ ├── constructor.clj │ │ ├── debug.clj │ │ ├── externals.clj │ │ ├── global.clj │ │ ├── parser.clj │ │ ├── printer.clj │ │ ├── re.clj │ │ ├── resolver.clj │ │ ├── runtime.clj │ │ ├── transformer.clj │ │ ├── transformers.clj │ │ ├── util.clj │ │ └── ysreader.clj │ └── ys │ │ ├── clj.clj │ │ ├── csv.clj │ │ ├── dwim.clj │ │ ├── ext.clj │ │ ├── json.clj │ │ ├── std.clj │ │ ├── taptest.clj │ │ ├── yaml.clj │ │ └── ys.clj └── test │ ├── compiler-stack.yaml │ ├── compiler.yaml │ ├── data-mode.yaml │ ├── resolver.yaml │ ├── runtime.yaml │ ├── transformer.yaml │ ├── yamlscript │ ├── builder_test.clj │ ├── compiler_test.clj │ ├── composer_test.clj │ ├── constructor_test.clj │ ├── parser_test.clj │ ├── printer_test.clj │ ├── resolver_test.clj │ ├── runtime_test.clj │ ├── test_runner.clj │ └── transformer_test.clj │ └── yamltest ├── crystal ├── .gitignore ├── Makefile ├── ReadMe.md ├── doc │ ├── authors.md │ └── readme.md ├── examples │ └── simple.cr ├── shard.yml ├── spec │ ├── spec_helper.cr │ └── yamlscript_spec.cr ├── src │ ├── yamlscript.cr │ └── yamlscript │ │ └── version.cr └── test │ └── ffi.cr ├── d ├── .gitignore ├── dub.json └── source │ └── app.d ├── doc ├── 4clojure.mdys ├── binary.md ├── bindings.md ├── capability.md ├── chain.md ├── cheat.md ├── cli.md ├── clj-to-ys.md ├── clojure.md ├── common.md ├── control.md ├── core.mdys ├── define.md ├── embedding.md ├── env-vars.md ├── examples.md ├── exercism.md ├── ext-libs.md ├── gotchas.md ├── index.md ├── install.md ├── intro.md ├── loaders.md ├── macros.md ├── mdys.ys ├── mode-tags.md ├── modes.md ├── multi-doc.md ├── operators.md ├── programming.md ├── query.md ├── referencing.md ├── run-ys.md ├── schema.md ├── syntax.md ├── templating.md ├── tutorial.md ├── v0.md ├── vocab.mdys ├── yaml.md ├── yes.md ├── ys-clj.md ├── ys-csv.mdys ├── ys-json.mdys ├── ys-libs.md ├── ys-std.mdys ├── ys-taptest.md ├── ys-yaml.mdys ├── ys-ys.md ├── ys.md └── ys4yaml.mdys ├── elixir ├── .formatter.exs ├── .gitignore ├── Makefile ├── README.md ├── lib │ └── yamlscript.ex ├── mix.exs ├── mix.lock └── test │ ├── test_helper.exs │ └── yamlscript_test.exs ├── go ├── .gitignore ├── Makefile ├── README ├── ReadMe.md ├── doc │ ├── authors.md │ └── readme.md ├── go.mod ├── go.sum ├── yamlscript.go └── yamlscript_test.go ├── java ├── Makefile ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── yamlscript │ │ └── yamlscript │ │ ├── ILibYAMLScript.java │ │ ├── LibYAMLScript.java │ │ └── YAMLScript.java │ ├── site │ └── site.xml │ └── test │ └── java │ └── org │ └── yamlscript │ └── yamlscript │ └── YAMLScriptTest.java ├── julia ├── .gitignore ├── LICENSE ├── Makefile ├── Project.toml ├── ReadMe.md ├── bin │ └── ys-yamlscript.jl ├── doc │ ├── authors.md │ └── readme.md ├── etc │ ├── ReadMe.md │ └── workflows │ │ └── julia.yaml ├── src │ ├── Function.jl │ ├── YAMLScript.jl │ └── libyamlscript.jl └── test │ └── runtests.jl ├── libyamlscript ├── .gitignore ├── Makefile ├── ReadMe.md ├── deps.edn ├── project.clj ├── reflection.json └── src │ └── libyamlscript │ ├── API.java │ └── core.clj ├── lua ├── .gitignore └── yamlscript-0.0.16.rockspec ├── nim ├── src │ ├── yamlscript.nim │ └── yamlscriptpkg │ │ └── submodule.nim ├── tests │ ├── config.nims │ └── test1.nim └── yamlscript.nimble ├── nodejs ├── .gitignore ├── Makefile ├── ReadMe.md ├── doc │ ├── authors.md │ └── readme.md ├── lib │ ├── @yaml │ └── yamlscript │ │ └── index.js ├── package.json └── test │ └── test.js ├── perl-alien ├── .gitignore ├── Changes ├── Makefile ├── Meta ├── alienfile ├── doc │ └── Alien │ │ └── YAMLScript.md ├── lib │ └── Alien │ │ └── YAMLScript.pm ├── pkg │ ├── make-cpan │ └── no-test └── test │ └── ffi.t ├── perl ├── .gitignore ├── Changes ├── Makefile ├── Meta ├── doc │ └── YAMLScript.md ├── lib │ ├── YAMLScript.pm │ └── YAMLScript │ │ └── Alien.pm └── test │ └── load.t ├── php ├── Changelog.md ├── License ├── ReadMe.md ├── YAMLScript.php └── composer.json ├── python ├── .gitignore ├── License ├── Makefile ├── ReadMe.md ├── doc │ ├── authors.md │ └── readme.md ├── lib │ └── yamlscript │ │ └── __init__.py ├── setup.cfg ├── setup.py └── test │ └── test.py ├── raku ├── .gitignore ├── META6.json ├── Makefile ├── README.md ├── lib │ └── YAMLScript.rakumod └── t │ ├── 00-use.rakutest │ └── 01-load.rakutest ├── ruby ├── .gitignore ├── ChangeLog.md ├── Gemfile ├── Makefile ├── Rakefile ├── ReadMe.md ├── doc │ ├── authors.md │ └── readme.md ├── lib │ ├── yamlscript.rb │ └── yamlscript │ │ └── version.rb ├── test │ └── lib │ │ └── yamlscript_test.rb └── yamlscript.gemspec ├── rust ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Makefile ├── ReadMe.md ├── doc │ ├── authors.md │ └── readme.md ├── examples │ └── eval_ys_to_json.rs ├── src │ ├── error.rs │ └── lib.rs └── tests │ └── load.rs ├── sample ├── advent │ ├── a-bit-of-data.ys │ ├── fruits.yaml │ ├── grocery.yaml │ ├── hearsay-rust │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── ReadMe.md │ │ ├── hearsay.ys │ │ └── src │ │ │ └── main.rs │ ├── hearsay.pl │ ├── hearsay.raku │ ├── hearsay.ys │ ├── lol.ys │ ├── madlibs │ ├── madlibs-data.yaml │ ├── silly.ys │ ├── thread-last.ys │ ├── tree.ys │ └── twas-a-bit ├── benchmark-yaml ├── blog │ └── 2024-03-25 │ │ ├── an-example.yaml │ │ ├── data.yaml │ │ └── rot13.ys ├── data.ys ├── food.yaml ├── github-issues │ └── issue-12.sh ├── readme │ ├── Cargo.lock │ ├── Cargo.toml │ ├── file.ys │ ├── other.yaml │ ├── prog.pl │ ├── prog.py │ ├── prog.raku │ ├── prog.rb │ ├── prog.rs │ ├── some.yaml │ ├── some.ys │ └── ys-load.js ├── rosetta-code │ ├── 100-doors.ys │ ├── 100-prisoners.ys │ ├── 99-bottles-of-beer.ys │ ├── average-loop-length.ys │ ├── factorial.ys │ ├── fibonacci-sequence.ys │ ├── fizzbuzz.ys │ ├── floyds-triangle.ys │ ├── function-definition.ys │ ├── greatest-common-divisor.ys │ ├── hello-world-text.ys │ ├── hello-world.ys │ ├── leap-year.ys │ ├── palindrome-detection.ys │ ├── rot-13.ys │ ├── sieve-of-eratosthenes.ys │ └── weird-numbers.ys ├── script.pl └── www │ ├── db-config.yaml │ ├── db-defaults.yaml │ ├── example.py │ ├── hello.ys │ └── secret.yaml ├── util ├── YSJ ├── brew-update ├── copy-md ├── mdys ├── mdys-md ├── release-assets ├── release-crystal ├── release-go ├── release-repo.bash ├── release-yamlscript └── version-bump ├── www ├── .gitignore ├── .vimrc ├── Makefile ├── config │ ├── about.yaml │ ├── blog-authors.yaml │ ├── blog.yaml │ ├── community.yaml │ ├── doc.yaml │ ├── learn.yaml │ ├── press.yaml │ ├── redirect.yaml │ ├── start.yaml │ ├── theme.yaml │ └── use.yaml ├── mkdocs.ys ├── requirements.txt ├── src │ ├── .gitignore │ ├── about-website.md │ ├── about.md │ ├── blog │ │ ├── .authors.yml │ │ └── index.md │ ├── cicd.md │ ├── circleci.md │ ├── community │ │ └── index.md │ ├── contrib-roadmap.md │ ├── contrib-rules.md │ ├── contrib-website.md │ ├── contrib │ │ └── index.md │ ├── css │ │ └── theme.css │ ├── faq.mdys │ ├── font │ │ └── AlexBrush-Regular.woff │ ├── gha.md │ ├── hacks.md │ ├── helmys.md │ ├── image │ │ ├── external-link.svg │ │ ├── favicon.ico │ │ ├── yamlscript-logo.svg │ │ └── yamlscript.svg │ ├── index.mdys │ ├── ingydotnet.md │ ├── install │ ├── install-libyamlscript │ ├── install-ys │ ├── json.md │ ├── kubeys24.md │ ├── mdys.ys │ ├── play.md │ ├── press.md │ ├── run-ys │ ├── site-testing.md │ ├── social.md │ ├── tprc2024.md │ ├── try-ys │ └── use │ │ └── index.md └── theme │ ├── ReadMe.md │ ├── main.html │ └── partials │ ├── actions.html │ ├── copyright.html │ └── header.html ├── yamltest └── src │ └── yamltest │ └── core.clj └── ys ├── .gitignore ├── Makefile ├── deps.edn ├── project.clj ├── reflection.json ├── share └── ys-0.bash ├── src └── yamlscript │ └── cli.clj └── test ├── a-symlink ├── advent.t ├── animals.json ├── chain.t ├── cli-usage.t ├── defn.t ├── dot.ys ├── empty-file ├── hello-world.ys ├── hello.ys ├── init ├── loader.ys ├── loadme.ys ├── merge-key.t ├── number.t ├── operators.t ├── process.t ├── rosetta-code.t ├── shebang1 ├── show-args ├── slice.t ├── std.t ├── str.t ├── taptest-failures.t ├── taptest-failures.ys ├── taptest.t ├── transform.t ├── unit-tests.t ├── yamlscript ├── cli_test.clj ├── getopts.clj └── test.clj └── ys.t /.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:lint-as {yamlscript.util/if-lets clojure.core/let 2 | yamlscript.builder clojure.core/let} 3 | :linters {:unresolved-symbol 4 | {:exclude-patterns ["^(_|condf|die|if-lets|when-lets|YSC)$"]}}} 5 | -------------------------------------------------------------------------------- /.cljfmt.edn: -------------------------------------------------------------------------------- 1 | #_:clj-kondo/ignore 2 | {:extra-indents {#"" [[:inner 0]]}} 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.ys linguist-language=yaml 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vimrc 2 | /*.clj 3 | /*.md 4 | *.md.tmp 5 | /*.yaml 6 | /*.ys 7 | /bin/ 8 | /homebrew-yamlscript/ 9 | /issue-* 10 | /lib/ 11 | /libyamlscript-* 12 | /release*.log 13 | /release-changes.txt 14 | /release-id.txt 15 | /website/ 16 | /work/ 17 | /ys-* 18 | /.tmp/ 19 | 20 | .calva/ 21 | *.class 22 | classes/ 23 | .clj-kondo/ 24 | .cpcache/ 25 | Dockerfile 26 | .DS_Store 27 | NO-NAME 28 | *.jar 29 | .lein-* 30 | .lsp/ 31 | note/ 32 | .nrepl-port 33 | .nrepl-pid 34 | pom.xml 35 | pom.xml.asc 36 | .portal/ 37 | .prepl-port 38 | profiles.clj 39 | .project.clj 40 | reports/ 41 | target/ 42 | .vscode/ 43 | .yamllm/ 44 | **/.idea/ 45 | -------------------------------------------------------------------------------- /.profile: -------------------------------------------------------------------------------- 1 | #! bash 2 | 3 | YAMLSCRIPT_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd -P) 4 | 5 | [[ $PATH == *$YAMLSCRIPT_ROOT/util:* ]] || 6 | export PATH=$YAMLSCRIPT_ROOT/util:$PATH 7 | -------------------------------------------------------------------------------- /.rc: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | 3 | YAMLSCRIPT_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd -P) 4 | 5 | [[ :$PATH: == *:"$YAMLSCRIPT_ROOT/install/bin":* ]] || 6 | PATH=$YAMLSCRIPT_ROOT/install/bin:$PATH 7 | 8 | [[ :$LD_LIBRARY_PATH: == *:"$YAMLSCRIPT_ROOT/install/lib":* ]] || 9 | LD_LIBRARY_PATH=$YAMLSCRIPT_ROOT/install/lib:$PATH 10 | 11 | # XXX This goes away after perl binding to libyamlscript is implemented. 12 | [[ :$PATH: == *:"$YAMLSCRIPT_ROOT/perl/bin":* ]] || 13 | PATH=$YAMLSCRIPT_ROOT/perl/bin:$PATH 14 | 15 | [[ :$PYTHONPATH: == *:"$YAMLSCRIPT_ROOT/python/lib":* ]] || 16 | PYTHONPATH=$YAMLSCRIPT_ROOT/python/lib 17 | 18 | export \ 19 | LD_LIBRARY_PATH \ 20 | PATH \ 21 | PYTHONPATH \ 22 | YAMLSCRIPT_ROOT \ 23 | 24 | +ys() ( 25 | set -x 26 | make -C $YAMLSCRIPT_ROOT/ys jar 27 | java -jar $YAMLSCRIPT_ROOT/ys/target/uberjar/yamlscript.cli-*-SNAPSHOT-standalone.jar "$@" 28 | ) 29 | 30 | test-ys-string() ( 31 | set -x 32 | python3 -c 'import sys,yamlscript; print(yamlscript.load(sys.argv[1]))' "$@" 33 | ) 34 | 35 | test-ys-file() ( 36 | set -x 37 | python3 -c 'import sys,yamlscript; print(yamlscript.load(open(sys.argv[1])))' "$@" 38 | ) 39 | 40 | # vim: ft=sh: 41 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.rulers": [80], 3 | "calva.fmt.configPath": ".cljfmt.edn", 4 | "cSpell.words": [ 5 | "devel", 6 | "mkdocs", 7 | "pymdownx", 8 | "svgexport", 9 | "twemoji", 10 | "VENV", 11 | "worktree", 12 | "yamlys", 13 | "yscode" 14 | ], 15 | "java.configuration.updateBuildConfiguration": "disabled", 16 | "makefile.configureOnOpen": true, 17 | "search.useIgnoreFiles": false, 18 | "git.ignoreLimitWarning": true 19 | } 20 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2025 Ingy döt Net and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Meta: -------------------------------------------------------------------------------- 1 | name: YAMLScript 2 | version: 0.1.96 3 | abstract: Program in YAML — Code is Data 4 | homepage: https://yamlscript.org 5 | license: mit 6 | copyright: 2022-2025 7 | 8 | author: 9 | name: Ingy döt Net 10 | email: ingy@ingy.net 11 | github: ingydotnet 12 | twitter: ingydotnet 13 | freenode: ingy 14 | homepage: http://ingy.net 15 | 16 | devel: 17 | git: https://github.com/yaml/yamlscript 18 | bug: https://github.com/yaml/yamlscript/issues 19 | irc: irc.libera.chat#yamlscript 20 | 21 | branch: main 22 | -------------------------------------------------------------------------------- /blog/welcome.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Welcome to the YS Blog 3 | date: 2023-10-26 4 | --- 5 | 6 | **Greetings!** 7 | 8 | Welcome to the YS blog. 9 | 10 | This is where we will introduce you to novel concepts about YS as the language 11 | evolves. 12 | -------------------------------------------------------------------------------- /clojure/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | include $(COMMON)/java.mk 4 | include $(COMMON)/clojure.mk 5 | 6 | export CLOJARS_USERNAME ?= $(shell util/get-setting username) 7 | export CLOJARS_PASSWORD ?= $(shell util/get-setting password) 8 | 9 | #------------------------------------------------------------------------------ 10 | 11 | test install deploy:: $(LEIN) $(YAMLSCRIPT_JAVA_INSTALLED) 12 | $< $@ 13 | 14 | release: deploy 15 | 16 | clean:: 17 | $(RM) pom.xml 18 | -------------------------------------------------------------------------------- /clojure/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"], 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.12.0"}, 4 | org.clojure/data.json {:mvn/version "2.4.0"}, 5 | org.json/json {:mvn/version "20240205"}, 6 | net.java.dev.jna/jna {:mvn/version "5.14.0"}, 7 | org.yamlscript/yamlscript {:mvn/version "0.1.96"}}} 8 | -------------------------------------------------------------------------------- /clojure/project.clj: -------------------------------------------------------------------------------- 1 | ;; This code is licensed under MIT license (See License for details) 2 | ;; Copyright 2023-2025 Ingy dot Net 3 | 4 | (defproject org.yamlscript/clj-yamlscript "0.1.96" 5 | :description 6 | "YAMLScript is a functional programming language whose syntax is encoded in 7 | YAML." 8 | 9 | :url "https://yamlscript.org" 10 | 11 | :license 12 | {:name "MIT" 13 | :url "https://opensource.org/license/mit/"} 14 | 15 | :scm 16 | {:name "git" 17 | :url "https://github.com/yaml/yamlscript" 18 | :tag "clojure" 19 | :dir ".."} 20 | 21 | :dependencies 22 | [[org.clojure/clojure "1.12.0"] 23 | [org.clojure/data.json "2.4.0"] 24 | [org.json/json "20240205"] 25 | [net.java.dev.jna/jna "5.14.0"] 26 | [org.yamlscript/yamlscript "0.1.96"]] 27 | 28 | :deploy-repositories 29 | [["releases" 30 | {:url "https://repo.clojars.org" 31 | :username :env/clojars_username 32 | :password :env/clojars_password 33 | :sign-releases false}]] 34 | 35 | :plugins 36 | [[lein-exec "0.3.7"] 37 | [reifyhealth/lein-git-down "0.4.1"] 38 | [dev.weavejester/lein-cljfmt "0.11.2"] 39 | [io.github.borkdude/lein-lein2deps "0.1.0"]] 40 | 41 | :prep-tasks [["lein2deps" "--write-file" "deps.edn" "--print" "false"]]) 42 | -------------------------------------------------------------------------------- /clojure/src/yamlscript/core.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.core 5 | (:require 6 | [clojure.data.json :as json]) 7 | (:refer-clojure :exclude [load]) 8 | (:import (org.yamlscript.yamlscript YAMLScript))) 9 | 10 | (defn load [ys-code] 11 | (let [result (json/read-str (.getRAWResult (YAMLScript.) ys-code)) 12 | data (result "data") 13 | error (result "error")] 14 | (cond 15 | error (throw (Exception. (error "cause"))) 16 | data data 17 | :else (throw 18 | (Exception. "Unexpected response from 'libyamlscript'"))))) 19 | 20 | (comment 21 | ) 22 | -------------------------------------------------------------------------------- /clojure/test/yamlscript/main_test.clj: -------------------------------------------------------------------------------- 1 | (ns yamlscript.main-test 2 | (:require 3 | [clojure.test :refer [deftest is]] 4 | [yamlscript.core :as ys])) 5 | 6 | (deftest load-test 7 | (let [data (ys/load "a: 1")] 8 | (is (= 1 (data "a"))))) 9 | -------------------------------------------------------------------------------- /clojure/util/get-setting: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | mvn_user_settings=~/.mvn-user-settings.xml 6 | 7 | grep "<$1>" "$mvn_user_settings" | 8 | perl -pe 's/.*>(.*)<.*/$1/' 9 | -------------------------------------------------------------------------------- /common/base.mk: -------------------------------------------------------------------------------- 1 | ifneq (GNU,$(firstword $(shell $(MAKE) --version))) 2 | $(error Error: 'make' must be 'GNU make') 3 | endif 4 | ifeq (,$(shell which bash)) 5 | $(error Error: 'bash' is required but not installed) 6 | endif 7 | 8 | SHELL := bash 9 | 10 | ROOT := $(shell \ 11 | cd '$(abspath $(dir $(lastword $(MAKEFILE_LIST))))/..' && pwd -P) 12 | 13 | export ROOT 14 | 15 | include $(ROOT)/common/vars.mk 16 | 17 | SUBDIR = $(shell pwd) 18 | SUBDIR := $(SUBDIR:$(ROOT)/%=%) 19 | 20 | export YSLANG := $(SUBDIR) 21 | 22 | 23 | #------------------------------------------------------------------------------ 24 | .SECONDEXPANSION: 25 | 26 | .DELETE_ON_ERROR: 27 | 28 | .PHONY: test 29 | 30 | #------------------------------------------------------------------------------ 31 | default:: 32 | 33 | build:: 34 | 35 | clean:: 36 | 37 | realclean:: clean 38 | 39 | distclean:: realclean 40 | 41 | chown:: 42 | $(MAKE) -C $(ROOT) $@ 43 | 44 | clean-all:: 45 | $(MAKE) -C $(ROOT) $@ 46 | 47 | always: 48 | 49 | env:: 50 | @env | sort | less -FRX 51 | -------------------------------------------------------------------------------- /common/binding.mk: -------------------------------------------------------------------------------- 1 | include $(COMMON)/vars-libys.mk 2 | 3 | test:: $(LIBYS_SO_FQNP) 4 | 5 | $(LIBYS_SO_FQNP): | $(ROOT)/libyamlscript 6 | $(MAKE) -C $(ROOT)/libyamlscript build 7 | 8 | build-doc:: build-bin 9 | 10 | build-bin: 11 | $(MAKE) -C $(ROOT) build-bin-ys 12 | 13 | clean:: 14 | $(RM) *.tmp 15 | 16 | ReadMe.md: $(COMMON)/readme.md $(wildcard doc/*.md) $(ROOT)/util/mdys 17 | mdys $< > $@.tmp 18 | mv $@.tmp $@ 19 | -------------------------------------------------------------------------------- /common/install.mk: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | 3 | ROOT := $(shell \ 4 | cd '$(abspath $(dir $(lastword $(MAKEFILE_LIST))))' && pwd -P) 5 | 6 | YAMLSCRIPT_VERSION := 0.1.96 7 | 8 | YS := $(wildcard ys) 9 | LIBYAMLSCRIPT := $(firstword $(wildcard libyamlscript.*)) 10 | 11 | PREFIX ?= /usr/local 12 | 13 | install: 14 | ifneq (,$(YS)) 15 | mkdir -p $(PREFIX)/bin 16 | cp -pP ys* $(PREFIX)/bin/ 17 | @echo 'Installed $(PREFIX)/bin/$(YS)' \ 18 | '- version $(YAMLSCRIPT_VERSION)' 19 | else ifneq (,$(LIBYAMLSCRIPT)) 20 | mkdir -p $(PREFIX)/lib 21 | cp -pP libyamlscript* $(PREFIX)/lib/ 22 | @echo 'Installed $(PREFIX)/lib/$(LIBYAMLSCRIPT)' \ 23 | '- version $(YAMLSCRIPT_VERSION)' 24 | else 25 | $(error Weird! Nothing to install in this directory.) 26 | endif 27 | -------------------------------------------------------------------------------- /common/java.mk: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # Set Java specific variables: 3 | #------------------------------------------------------------------------------ 4 | 5 | export JAVA_HOME := $(GRAALVM_HOME) 6 | export PATH := $(JAVA_HOME)/bin:$(PATH) 7 | 8 | YAMLSCRIPT_JAVA_INSTALLED := \ 9 | $(MAVEN_REPOSITORY)/org/yamlscript/yamlscript/maven-metadata-local.xml 10 | 11 | YAMLSCRIPT_JAVA_SRC := \ 12 | $(ROOT)/java/src/main/java/org/yamlscript/yamlscript/*.java \ 13 | 14 | 15 | #------------------------------------------------------------------------------ 16 | java-home: 17 | @echo $(JAVA_HOME) 18 | 19 | $(GRAALVM_HOME): $(GRAALVM_INSTALLED) 20 | 21 | $(GRAALVM_INSTALLED): $(GRAALVM_DOWNLOAD) 22 | tar xzf $< 23 | mv graalvm-* $(GRAALVM_PATH) 24 | touch $@ 25 | 26 | $(GRAALVM_DOWNLOAD): 27 | $(call need-curl) 28 | $(CURL) -o $@ $(GRAALVM_URL) 29 | 30 | $(YAMLSCRIPT_JAVA_INSTALLED): $(YAMLSCRIPT_JAVA_SRC) 31 | $(MAKE) -C $(ROOT)/java install 32 | -------------------------------------------------------------------------------- /common/python.mk: -------------------------------------------------------------------------------- 1 | PYTHON := $(shell command -v python3) 2 | PYTHON ?= $(shell command -v python) 3 | -------------------------------------------------------------------------------- /common/release.md: -------------------------------------------------------------------------------- 1 | 2 | [YS](https://yamlscript.org) publishes binary releases for the `ys` command line tool and for the `libyamlscript` shared library. 3 | The following architectures are currently supported: 4 | 5 | * Linux / Intel and ARM 6 | * macOS / Intel and ARM 7 | 8 | Run this command to install `~/.local/bin/ys`: 9 | 10 | ``` 11 | $ curl https://getys.org/ys | bash 12 | ``` 13 | 14 | See [Installing YS](https://yamlscript.org/doc/install/) for more detailed information about installing YS things. 15 | 16 | 17 | ## Changes in YS version 0.1.96 18 | 19 | -------------------------------------------------------------------------------- /common/vars-cli.mk: -------------------------------------------------------------------------------- 1 | include $(COMMON)/vars-core.mk 2 | 3 | CLI_BIN := bin/ys-$(YS_VERSION) 4 | CLI_SRC := \ 5 | src/yamlscript/cli.clj \ 6 | 7 | CLI_BIN_BASH := bin/ys-sh-$(YS_VERSION) 8 | CLI_BIN_BASH_SRC := share/ys-0.bash 9 | 10 | CLI_JAR := \ 11 | target/uberjar/yamlscript.cli-$(YS_VERSION)-SNAPSHOT-standalone.jar 12 | 13 | CLI_JAR_DEPS := \ 14 | $(LEIN) \ 15 | $(CORE_INSTALLED) \ 16 | $(CLI_SRC) \ 17 | 18 | CLI_DEPS := \ 19 | $(CLI_BIN) \ 20 | $(CLI_BIN_BASH) \ 21 | 22 | ifdef YS_NATIVE_BUILD_STATIC 23 | ifeq (true,$(IS_LINUX)) 24 | ifeq (true,$(IS_INTEL)) 25 | CLI_DEPS := $(MUSL_GCC) $(CLI_DEPS) 26 | NATIVE_OPTS += \ 27 | -H:CCompilerOption=-Wl,-z,stack-size=2097152 \ 28 | --static \ 29 | --libc=musl 30 | endif 31 | endif 32 | endif 33 | -------------------------------------------------------------------------------- /common/vars-core.mk: -------------------------------------------------------------------------------- 1 | CORE_DIR := $(ROOT)/core 2 | CORE_JAR := $(CORE_DIR)/target/core-$(YAMLSCRIPT_VERSION)-standalone.jar 3 | CORE_DEPS := $(LEIN) $(shell find $(CORE_DIR)/src -name '*.clj') 4 | 5 | CORE_INSTALLED := \ 6 | $(MAVEN_REPOSITORY)/yamlscript/core/$(YAMLSCRIPT_VERSION) 7 | CORE_INSTALLED := \ 8 | $(CORE_INSTALLED)/core-$(YAMLSCRIPT_VERSION).jar 9 | -------------------------------------------------------------------------------- /common/vars-libys.mk: -------------------------------------------------------------------------------- 1 | LIBYS_DIR := $(ROOT)/libyamlscript 2 | LIBYS_LIB := $(LIBYS_DIR)/lib 3 | 4 | export LD_LIBRARY_PATH := $(LIBYS_LIB):$(LD_LIBRARY_PATH) 5 | export $(DY)LD_LIBRARY_PATH := $(LD_LIBRARY_PATH) 6 | 7 | LIBYS_SO_NAME := $(LIBYS_LIB)/libyamlscript 8 | LIBYS_SO_FQNP := $(LIBYS_SO_NAME).$(SO).$(YAMLSCRIPT_VERSION) 9 | LIBYS_SO_BASE := $(LIBYS_LIB)/libyamlscript.$(SO) 10 | LIBYS_SO_APIP := $(LIBYS_SO_BASE).$(API_VERSION) 11 | LIBYS_SO_VERS := $(LIBYS_LIB)/libyamlscript.$(YAMLSCRIPT_VERSION).$(SO) 12 | 13 | LIBYS_DEPS := \ 14 | $(LIBYS_SO_FQNP) \ 15 | 16 | LIBYS_JAR := \ 17 | $(LIBYS_LIB)/target/libyamlscript-$(YAMLSCRIPT_VERSION)-standalone.jar 18 | 19 | LIBYS_INSTALLED := \ 20 | $(MAVEN_REPOSITORY)/org/yamlscript/yamlscript/$(YAMLSCRIPT_VERSION) 21 | LIBYS_INSTALLED := \ 22 | $(LIBYS_INSTALLED)/yamlscript-$(YAMLSCRIPT_VERSION).jar 23 | 24 | LIBYS_JAR_PATH := \ 25 | target/libyamlscript-$(YAMLSCRIPT_VERSION)-standalone.jar 26 | 27 | LIBYS_SOURCES := \ 28 | src/libyamlscript/core.clj \ 29 | src/libyamlscript/API.java \ 30 | 31 | LIBYS_HEADERS := \ 32 | $(LIBYS_LIB)/graal_isolate.h \ 33 | $(LIBYS_SO_NAME).$(YAMLSCRIPT_VERSION).h \ 34 | -------------------------------------------------------------------------------- /common/zild.mk: -------------------------------------------------------------------------------- 1 | ZILD_COMMANDS := \ 2 | cpan \ 3 | cpanshell \ 4 | dist \ 5 | distdir \ 6 | distshell \ 7 | disttest \ 8 | install \ 9 | release \ 10 | update \ 11 | 12 | ifneq (,$(shell command -v zild)) 13 | $(ZILD_COMMANDS):: 14 | zild $@ 15 | endif 16 | -------------------------------------------------------------------------------- /core/License: -------------------------------------------------------------------------------- 1 | ../License -------------------------------------------------------------------------------- /core/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/java.mk 3 | include $(COMMON)/clojure.mk 4 | include $(COMMON)/vars-core.mk 5 | 6 | export PATH := $(ROOT)/core/bin:$(PATH) 7 | 8 | #------------------------------------------------------------------------------ 9 | build:: 10 | 11 | test:: $(CORE_DEPS) 12 | $(LEIN) $@ 13 | 14 | install: $(CORE_INSTALLED) 15 | 16 | $(CORE_INSTALLED): $(CORE_DEPS) 17 | $(LEIN) install 18 | touch $@ 19 | 20 | $(CORE_JAR): $(CORE_DEPS) 21 | $(LEIN) uberjar 22 | touch $@ 23 | 24 | clean:: 25 | $(RM) pom.xml 26 | $(RM) -r target/ 27 | -------------------------------------------------------------------------------- /core/ReadMe.md: -------------------------------------------------------------------------------- 1 | yamlscript/core 2 | =============== 3 | 4 | The YS compiler and runtime written in Clojure 5 | 6 | 7 | ## Synopsis 8 | 9 | ```clojure 10 | (do 11 | (require '[yamlscript.compiler :as ys]) 12 | (-> "foo: bar baz" 13 | ys/compile)) 14 | => "(foo bar baz)\n" 15 | ``` 16 | 17 | 18 | ## Description 19 | 20 | This directory builds the YS language written in Clojure. 21 | 22 | The `yamlscript.compiler/compile` function takes a YS input string and compiles 23 | it to a Clojure code string. 24 | 25 | 26 | ## Makefile usage 27 | 28 | * `make test` 29 | 30 | This runs the test suite. 31 | Run with `make test v=1` for verbose output. 32 | Run with `w=1` to show reflection warnings. 33 | -------------------------------------------------------------------------------- /core/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"], 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.12.0"}, 4 | org.clojure/data.csv {:mvn/version "1.1.0"}, 5 | org.clojure/data.json {:mvn/version "2.4.0"}, 6 | clj-commons/clj-yaml {:mvn/version "1.0.27"}, 7 | org.flatland/ordered {:mvn/version "1.15.11"}, 8 | org.snakeyaml/snakeyaml-engine {:mvn/version "2.7"}, 9 | babashka/babashka.pods {:mvn/version "0.2.0"}, 10 | babashka/fs {:mvn/version "0.5.20"}, 11 | babashka/process {:mvn/version "0.5.21"}, 12 | org.clj-commons/digest {:mvn/version "1.4.100"}, 13 | org.babashka/http-client {:mvn/version "0.3.11"}, 14 | org.babashka/sci {:mvn/version "0.8.41"}, 15 | org.clojure/tools.cli {:mvn/version "1.0.219"}, 16 | clojure.java-time/clojure.java-time {:mvn/version "1.4.3"}}, 17 | :mvn/repos {"public-github" {:url "https://github.com"}}} 18 | -------------------------------------------------------------------------------- /core/project.clj: -------------------------------------------------------------------------------- 1 | ;; This code is licensed under MIT license (See License for details) 2 | ;; Copyright 2023-2025 Ingy dot Net 3 | 4 | (defproject yamlscript/core "0.1.96" 5 | :description "Program in YAML — Code is Data" 6 | 7 | :url "https://github.com/yaml/yamlscript" 8 | 9 | :license 10 | {:name "MIT" 11 | :url "https://opensource.org/license/mit/"} 12 | 13 | :scm 14 | {:name "git" 15 | :url "https://github.com/yaml/yamlscript" 16 | :tag "clojure" 17 | :dir ".."} 18 | 19 | :dependencies 20 | [[org.clojure/clojure "1.12.0"] 21 | [org.clojure/data.csv "1.1.0"] 22 | [org.clojure/data.json "2.4.0"] 23 | [clj-commons/clj-yaml "1.0.27"] 24 | [org.flatland/ordered "1.15.11"] 25 | [org.snakeyaml/snakeyaml-engine "2.7"] 26 | [babashka/babashka.pods "0.2.0"] 27 | [babashka/fs "0.5.20"] 28 | [babashka/process "0.5.21"] 29 | [org.clj-commons/digest "1.4.100"] 30 | [org.babashka/http-client "0.3.11"] 31 | [org.babashka/sci "0.8.41"] 32 | [org.clojure/tools.cli "1.0.219"] 33 | [clojure.java-time "1.4.3"]] 34 | 35 | :plugins 36 | [[lein-exec "0.3.7"] 37 | [reifyhealth/lein-git-down "0.4.1"] 38 | [dev.weavejester/lein-cljfmt "0.11.2"] 39 | [io.github.borkdude/lein-lein2deps "0.1.0"]] 40 | 41 | :prep-tasks [["lein2deps" "--write-file" "deps.edn" "--print" "false"]] 42 | 43 | :repositories [["public-github" {:url "https://github.com"}]] 44 | 45 | :global-vars {*warn-on-reflection* true} 46 | 47 | :profiles 48 | {:dev 49 | {:dependencies 50 | [[pjstadig/humane-test-output "0.11.0"]] 51 | :injections [(require 'pjstadig.humane-test-output) 52 | (pjstadig.humane-test-output/activate!)]} 53 | 54 | :repl 55 | {:repl-options 56 | {:init 57 | (do 58 | (require 'pjstadig.humane-test-output) 59 | (pjstadig.humane-test-output/activate!) 60 | (require 'yamlscript.test-runner))}}}) 61 | -------------------------------------------------------------------------------- /core/resources/_: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaml/yamlscript/b47d953d40bb3dec8065e1fed45eb531b1acad0a/core/resources/_ -------------------------------------------------------------------------------- /core/src/yamlscript/cache.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.cache 5 | (:require 6 | [babashka.fs :as fs] 7 | [babashka.http-client :as http] 8 | [clj-commons.digest :as digest]) 9 | (:refer-clojure :exclude [get set])) 10 | 11 | (defn ys-cache [] 12 | (or (System/getenv "YS_CACHE") 13 | "/tmp/ys-cache")) 14 | 15 | (defn ys-cache-dir [] 16 | (let [ys-cache (ys-cache)] 17 | (when-not (fs/exists? ys-cache) 18 | (fs/create-dir ys-cache)) 19 | ys-cache)) 20 | 21 | (defn get [key] 22 | (let [sha1 (digest/sha1 key) 23 | ys-cache-dir (ys-cache-dir) 24 | cache (str ys-cache-dir "/" sha1)] 25 | (when (fs/exists? cache) 26 | (slurp cache)))) 27 | 28 | (defn set [key val] 29 | (let [sha1 (digest/sha1 key) 30 | ys-cache-dir (ys-cache-dir) 31 | cache (str ys-cache-dir "/" sha1)] 32 | (spit cache val) 33 | val)) 34 | 35 | (defn curl [url] 36 | (or (get url) 37 | (let [resp (http/get url) 38 | text (if-let [body (:body resp)] 39 | (str body) 40 | (die resp))] 41 | (set url text)))) 42 | 43 | (comment 44 | ) 45 | -------------------------------------------------------------------------------- /core/src/ys/clj.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | ;; This library contains the clojure.core functions that are replaced by the 5 | ;; ys::std library. 6 | ;; They can be accessed with clj/foo instead of foo. 7 | 8 | (ns ys.clj 9 | (:refer-clojure :only [intern])) 10 | 11 | (intern 'ys.clj 'compile clojure.core/compile) 12 | (intern 'ys.clj 'eval clojure.core/eval) 13 | (intern 'ys.clj 'load clojure.core/load) 14 | (intern 'ys.clj 'load-file clojure.core/load-file) 15 | (intern 'ys.clj 'print clojure.core/print) 16 | (intern 'ys.clj 'read clojure.core/read) 17 | (intern 'ys.clj 'use clojure.core/use) 18 | -------------------------------------------------------------------------------- /core/src/ys/csv.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns ys.csv 5 | (:require 6 | [clojure.data.csv :as csv] 7 | [clojure.string :as str]) 8 | (:refer-clojure :exclude [read])) 9 | 10 | (defn read-csv [s] 11 | (csv/read-csv (str/trim-newline s) :separator \,)) 12 | 13 | (defn read-tsv [s] 14 | (csv/read-csv (str/trim-newline s) :separator \tab)) 15 | 16 | (defn write-csv [data] 17 | (with-open [s (java.io.StringWriter.)] 18 | (csv/write-csv s data :separator \,) 19 | (str s))) 20 | 21 | (defn write-tsv [data] 22 | (with-open [s (java.io.StringWriter.)] 23 | (csv/write-csv s data :separator \tab) 24 | (str s))) 25 | 26 | (defn read [s] 27 | (read-csv s)) 28 | 29 | (defn write [data] 30 | (write-csv data)) 31 | 32 | (comment 33 | ) 34 | -------------------------------------------------------------------------------- /core/src/ys/ext.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns ys.ext 5 | (:require 6 | [clojure.string :as str] 7 | [babashka.process :as process] 8 | [yamlscript.util :as util] 9 | [ys.yaml :as yaml])) 10 | 11 | (defn github-raw-url [spec] 12 | (let [[owner repo ref & path] (str/split spec #"/")] 13 | (format 14 | "https://raw.githubusercontent.com/%s/%s/refs/heads/%s/%s" 15 | owner repo ref (str/join "/" path)))) 16 | 17 | (defn yq [data cmd] 18 | (let [yaml (yaml/dump data) 19 | res (process/sh {:in yaml} 20 | "yq" "-e" cmd) 21 | {:keys [exit out err]} res] 22 | (when (and 23 | (not= 0 exit) 24 | (not= err "Error: no matches found\n")) 25 | (util/die "yq error: " (:err res))) 26 | 27 | (let [data (if (str/blank? out) 28 | nil 29 | (yaml/load-all out))] 30 | (if (= 1 (count data)) 31 | (first data) 32 | data)))) 33 | 34 | (comment 35 | ) 36 | -------------------------------------------------------------------------------- /core/src/ys/json.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns ys.json 5 | (:require 6 | [clojure.data.json :as json]) 7 | (:refer-clojure :exclude [load])) 8 | 9 | (defn load [str] 10 | (json/read-str str)) 11 | 12 | (defn dump [data] 13 | (json/write-str data)) 14 | 15 | (defn pretty [data] 16 | (with-out-str 17 | (json/pprint data))) 18 | 19 | (comment 20 | ) 21 | -------------------------------------------------------------------------------- /core/src/ys/yaml.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns ys.yaml 5 | (:require 6 | [clojure.string :as str] 7 | [clj-yaml.core :as yaml]) 8 | (:refer-clojure :exclude [load]) 9 | #_(:import 10 | (java.util Optional) 11 | (org.snakeyaml.engine.v2.api DumpSettings) 12 | (org.snakeyaml.engine.v2.api.lowlevel Parse) 13 | )) 14 | 15 | (def prefix-re 16 | #"(?x)^ 17 | (?: 18 | (?:\s*\#.*\n) # skip comments 19 | | 20 | (?:\s*\n) # skip blank lines 21 | )* 22 | ---\s+") 23 | 24 | (defn load [str] 25 | (yaml/parse-string str 26 | :code-point-limit (* 10 1024 1024) 27 | :keywords false)) 28 | 29 | (defn load-all [str] 30 | (let [str (str/replace str prefix-re "") 31 | documents (str/split str #"(?m)^---\s+")] 32 | (reduce 33 | (fn [data doc] 34 | (conj data (load doc))) 35 | [] 36 | documents))) 37 | 38 | (defn dump [data] 39 | (yaml/generate-string 40 | data 41 | :dumper-options 42 | {:flow-style :block})) 43 | 44 | (defn dump-all [data] 45 | (str/join "\n" 46 | (reduce 47 | (fn [strings node] 48 | (conj strings 49 | (let [yaml (str/trimr 50 | (yaml/generate-string node 51 | :dumper-options 52 | {:flow-style :block}))] 53 | (if (> (count data) 1) 54 | (str "---\n" yaml) 55 | yaml)))) 56 | [] data))) 57 | 58 | (comment 59 | ) 60 | -------------------------------------------------------------------------------- /core/test/runtime.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023-2025 Ingy dot Net 2 | # This code is licensed under MIT license (See License for details) 3 | 4 | 5 | - name: Atoms 6 | ys: | 7 | vector: 8 | =>: 1 9 | =>: 2.3 10 | =>: "foo" 11 | =>: true 12 | =>: false 13 | =>: -[1 2 3] 14 | =>: -{:a 1 :b 2} 15 | eval: | 16 | [1 2.3 "foo" true false [1 2 3] {:a 1, :b 2}] 17 | 18 | 19 | - name: Operator + combinations 20 | ys: | 21 | vector: 22 | =>: 1 + 2 23 | =>: 1 + 2 + 3 24 | =>: -"foo" + "bar" 25 | =>: -[1 2] + [3 4] 26 | eval: | 27 | [3 6 "foobar" (1 2 3 4)] 28 | 29 | 30 | - name: Dot threading 31 | ys: | 32 | n =: 10 33 | =>: n.inc().vector().repeat(3) 34 | .flatten().repeat(2) 35 | .flatten().take(5) 36 | eval: | 37 | [11 11 11 11 11] 38 | -------------------------------------------------------------------------------- /core/test/yamlscript/builder_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.builder-test 5 | (:require 6 | [clojure.edn :as edn] 7 | [yamlscript.builder :as builder] 8 | [yamlscript.common] 9 | [yamlscript.composer :as composer] 10 | [yamlscript.parser :as parser] 11 | [yamlscript.resolver :as resolver] 12 | [yamltest.core :as test])) 13 | 14 | (test/load-yaml-test-files 15 | ["test/compiler-stack.yaml" 16 | "test/compiler.yaml" 17 | "test/data-mode.yaml" 18 | "test/transformer.yaml"] 19 | {:pick #(test/has-keys? [:yamlscript :build] %1) 20 | :test (fn [test] 21 | (-> test 22 | :yamlscript 23 | parser/parse 24 | composer/compose 25 | first 26 | resolver/resolve 27 | builder/build)) 28 | :want (fn [test] 29 | (-> test 30 | :build 31 | edn/read-string))}) 32 | -------------------------------------------------------------------------------- /core/test/yamlscript/compiler_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.compiler-test 5 | (:require 6 | [clojure.string :as str] 7 | [yamlscript.common] 8 | [yamlscript.compiler :as compiler] 9 | [yamltest.core :as test])) 10 | 11 | (defn testing-fix-clojure [clj] 12 | (-> clj 13 | (str/replace #"(?m)^\(\+\+\+ +(.*)\)$" "$1") 14 | (str/replace #"(?s)^\(\+\+\+[ \n]+(.*)\)$" "$1"))) 15 | 16 | (test/load-yaml-test-files 17 | ["test/compiler.yaml" 18 | "test/compiler-stack.yaml" 19 | "test/transformer.yaml"] 20 | {:pick #(test/has-keys? [:yamlscript :clojure] %1) 21 | :test (fn [test] 22 | (-> test 23 | :yamlscript 24 | compiler/compile 25 | compiler/pretty-format 26 | testing-fix-clojure)) 27 | :want :clojure}) 28 | 29 | (test/load-yaml-test-files 30 | ["test/compiler.yaml"] 31 | {:add-tests true 32 | :pick #(test/has-keys? [:yamlscript :error] %1) 33 | :test (fn [test] 34 | (try 35 | (-> test 36 | :yamlscript 37 | compiler/compile) 38 | "" 39 | (catch Exception e 40 | (:cause (Throwable->map e))))) 41 | :want :error}) 42 | -------------------------------------------------------------------------------- /core/test/yamlscript/composer_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.composer-test 5 | (:require 6 | [clojure.edn :as edn] 7 | [yamlscript.common] 8 | [yamlscript.composer :as composer] 9 | [yamlscript.parser :as parser] 10 | [yamltest.core :as test])) 11 | 12 | (test/load-yaml-test-files 13 | ["test/compiler-stack.yaml" 14 | "test/resolver.yaml" 15 | "test/compiler.yaml"] 16 | {:pick #(test/has-keys? [:yamlscript :compose] %1) 17 | :test (fn [test] 18 | (-> test 19 | :yamlscript 20 | parser/parse 21 | composer/compose 22 | first)) 23 | :want (fn [test] 24 | (-> test 25 | :compose 26 | edn/read-string))}) 27 | 28 | #_(test/load-yaml-test-files 29 | ["test/compiler-stack.yaml"] 30 | {:add-tests true 31 | :pick #(test/has-keys? [:yamlscript :compose-error] %1) 32 | :test (fn [test] 33 | (try 34 | (-> test 35 | :yamlscript 36 | parser/parse 37 | composer/compose 38 | first) 39 | "" 40 | (catch Exception e 41 | (:cause (Throwable->map e))))) 42 | :want :compose-error}) 43 | -------------------------------------------------------------------------------- /core/test/yamlscript/constructor_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.constructor-test 5 | (:require 6 | [clojure.edn :as edn] 7 | [yamlscript.builder :as builder] 8 | [yamlscript.common] 9 | [yamlscript.composer :as composer] 10 | [yamlscript.constructor :as constructor] 11 | [yamlscript.parser :as parser] 12 | [yamlscript.resolver :as resolver] 13 | [yamlscript.transformer :as transformer] 14 | [yamltest.core :as test])) 15 | 16 | (test/load-yaml-test-files 17 | ["test/compiler-stack.yaml" 18 | "test/data-mode.yaml" 19 | "test/compiler.yaml"] 20 | {:pick #(test/has-keys? [:yamlscript :construct] %1) 21 | :test (fn [test] 22 | (-> test 23 | :yamlscript 24 | parser/parse 25 | composer/compose 26 | first 27 | resolver/resolve 28 | builder/build 29 | transformer/transform 30 | constructor/construct-ast)) 31 | :want (fn [test] 32 | (-> test 33 | :construct 34 | edn/read-string))}) 35 | -------------------------------------------------------------------------------- /core/test/yamlscript/parser_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.parser-test 5 | (:require 6 | [clojure.string :as str] 7 | [yamlscript.common] 8 | [yamlscript.parser :as parser] 9 | [yamltest.core :as test])) 10 | 11 | (test/load-yaml-test-files 12 | ["test/compiler-stack.yaml" 13 | "test/resolver.yaml" 14 | "test/data-mode.yaml"] 15 | {:pick #(test/has-keys? [:yamlscript :parse] %1) 16 | :test (fn [test] 17 | (->> test 18 | :yamlscript 19 | parser/parse-test-case 20 | (map pr-str) 21 | (map #(subs %1 4 (dec (count %1)))))) 22 | :want (fn [test] 23 | (-> test 24 | :parse 25 | str/split-lines))}) 26 | -------------------------------------------------------------------------------- /core/test/yamlscript/printer_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.printer-test 5 | (:require 6 | [yamlscript.builder :as builder] 7 | [yamlscript.common] 8 | [yamlscript.compiler :as compiler] 9 | [yamlscript.composer :as composer] 10 | [yamlscript.constructor :as constructor] 11 | [yamlscript.parser :as parser] 12 | [yamlscript.printer :as printer] 13 | [yamlscript.resolver :as resolver] 14 | [yamlscript.transformer :as transformer] 15 | [yamltest.core :as test])) 16 | 17 | (test/load-yaml-test-files 18 | ["test/compiler-stack.yaml" 19 | "test/data-mode.yaml" 20 | "test/compiler.yaml"] 21 | {:pick #(test/has-keys? [:yamlscript :print] %1) 22 | :test (fn [test] 23 | (-> test 24 | :yamlscript 25 | parser/parse 26 | composer/compose 27 | first 28 | resolver/resolve 29 | builder/build 30 | transformer/transform 31 | constructor/construct-ast 32 | printer/print 33 | compiler/pretty-format)) 34 | :want :print}) 35 | -------------------------------------------------------------------------------- /core/test/yamlscript/resolver_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.resolver-test 5 | (:require 6 | [clojure.edn :as edn] 7 | [yamlscript.common] 8 | [yamlscript.composer :as composer] 9 | [yamlscript.parser :as parser] 10 | [yamlscript.resolver :as resolver] 11 | [yamltest.core :as test])) 12 | 13 | (test/load-yaml-test-files 14 | ["test/compiler-stack.yaml" 15 | "test/data-mode.yaml" 16 | "test/resolver.yaml" 17 | "test/compiler.yaml"] 18 | {:pick #(test/has-keys? [:yamlscript :resolve] %1) 19 | :test (fn [test] 20 | (try 21 | (-> test 22 | :yamlscript 23 | parser/parse 24 | composer/compose 25 | first 26 | resolver/resolve) 27 | (catch Exception e 28 | (if (:error test) 29 | (.getMessage e) 30 | (throw e))))) 31 | :want (fn [test] 32 | (-> test 33 | :resolve 34 | edn/read-string))}) 35 | -------------------------------------------------------------------------------- /core/test/yamlscript/runtime_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.runtime-test 5 | (:require 6 | [clojure.edn :as edn] 7 | [yamlscript.compiler :as compiler] 8 | [yamlscript.runtime :as runtime] 9 | [yamltest.core :as test])) 10 | 11 | (test/load-yaml-test-files 12 | ["test/runtime.yaml"] 13 | {:pick #(test/has-keys? [:ys :eval] %1) 14 | :test (fn [test] 15 | (-> test 16 | :ys 17 | (->> (str "!yamlscript/v0\n")) 18 | compiler/compile 19 | runtime/eval-string)) 20 | :want (fn [test] 21 | (-> test 22 | :eval 23 | edn/read-string))}) 24 | -------------------------------------------------------------------------------- /core/test/yamlscript/test_runner.clj: -------------------------------------------------------------------------------- 1 | ;; This code is licensed under MIT license (See License for details) 2 | ;; Copyright 2023-2025 Ingy dot Net 3 | 4 | (ns yamlscript.test-runner 5 | (:require 6 | [yamltest.core :as test] 7 | [yamlscript.global :as global] 8 | [yamlscript.builder-test] 9 | [yamlscript.compiler-test] 10 | [yamlscript.composer-test] 11 | [yamlscript.constructor-test] 12 | [yamlscript.parser-test] 13 | [yamlscript.printer-test] 14 | [yamlscript.resolver-test] 15 | [yamlscript.transformer-test])) 16 | 17 | (swap! global/opts assoc :unordered true) 18 | 19 | (comment 20 | ;; Pick a namespace to run tests in (:all will always run all tests): 21 | (in-ns 'yamlscript.compiler-test) 22 | 23 | ;; eval one of these forms to run tests: 24 | (test/run :a :v) 25 | 26 | @test/test-nss 27 | 28 | (test/run) 29 | 30 | (test/run 3 2 1 :v) 31 | 32 | (test/run :verbose) 33 | (test/run :all) 34 | (test/run :all :verbose :reload) 35 | (test/run :verbose :reload) 36 | ) 37 | -------------------------------------------------------------------------------- /core/test/yamlscript/transformer_test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.transformer-test 5 | (:require 6 | [yamlscript.builder :as builder] 7 | [yamlscript.common] 8 | [yamlscript.composer :as composer] 9 | [yamlscript.parser :as parser] 10 | [yamlscript.resolver :as resolver] 11 | [yamlscript.transformer :as transformer] 12 | [yamltest.core :as test] 13 | [clojure.edn :as edn])) 14 | 15 | (test/load-yaml-test-files 16 | ["test/compiler-stack.yaml" 17 | "test/compiler.yaml" 18 | "test/transformer.yaml"] 19 | {:pick #(test/has-keys? [:yamlscript :transform] %1) 20 | :test (fn [test] 21 | (-> test 22 | :yamlscript 23 | parser/parse 24 | composer/compose 25 | first 26 | resolver/resolve 27 | builder/build 28 | transformer/transform)) 29 | :want (fn [test] 30 | (-> test 31 | :transform 32 | edn/read-string))}) 33 | 34 | (test/load-yaml-test-files 35 | ["test/transformer.yaml"] 36 | {:add-tests true 37 | :pick #(test/has-keys? [:yamlscript :error] %1) 38 | :test (fn [test] 39 | (try 40 | (-> test 41 | :yamlscript 42 | parser/parse 43 | composer/compose 44 | first 45 | resolver/resolve 46 | builder/build 47 | transformer/transform) 48 | "" 49 | (catch Exception e 50 | (:cause (Throwable->map e))))) 51 | :want :error}) 52 | -------------------------------------------------------------------------------- /core/test/yamltest: -------------------------------------------------------------------------------- 1 | ../../yamltest/src/yamltest -------------------------------------------------------------------------------- /crystal/.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | /.shards/ 3 | /docs/ 4 | /spec/.env 5 | /.crystal/ 6 | /bin/ 7 | /samples/ 8 | *.dwarf 9 | /shard.lock 10 | # Don't accidentally commit shared library files 11 | libyamlscript.so* 12 | # Shell scripts that are for development only 13 | run_example.sh 14 | # Logs and other temporary files 15 | *.log 16 | *.tmp 17 | -------------------------------------------------------------------------------- /crystal/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | 4 | # Define crystal command 5 | ifneq (,$(shell command -v crystal)) 6 | CRYSTAL ?= crystal 7 | endif 8 | 9 | BASE := $(ROOT)/crystal 10 | 11 | LIBYS_SO_PATH := $(ROOT)/libyamlscript/lib/$(LIBYS_SO_FQNP) 12 | BUILD_DEPS := $(LIBYS_SO_PATH) 13 | 14 | #------------------------------------------------------------------------------ 15 | 16 | build:: build-doc 17 | 18 | build-doc:: ReadMe.md 19 | 20 | ifdef CRYSTAL 21 | test:: test-example test-crystal test-ffi 22 | endif 23 | 24 | test-example: $(BUILD_DEPS) 25 | $(CRYSTAL) run examples/simple.cr 26 | 27 | test-crystal: $(BUILD_DEPS) 28 | $(CRYSTAL) spec 29 | 30 | test-ffi: $(BUILD_DEPS) 31 | $(CRYSTAL) run test/ffi.cr 32 | 33 | release: 34 | $(ROOT)/util/release-crystal 35 | 36 | clean:: 37 | $(RM) -r lib bin .crystal .shards shard.lock libyamlscript.so 38 | 39 | $(LIBYS_SO_PATH): 40 | $(MAKE) -C $(ROOT)/libyamlscript $(LIBYS_SO_FQNP) 41 | -------------------------------------------------------------------------------- /crystal/doc/authors.md: -------------------------------------------------------------------------------- 1 | * [Josephine Pfeiffer](https://github.com/pfeifferj) 2 | * [Ingy döt Net](https://github.com/ingydotnet) 3 | -------------------------------------------------------------------------------- /crystal/doc/readme.md: -------------------------------------------------------------------------------- 1 | ## Crystal Usage 2 | 3 | Here's a simple example of using the YAMLScript Crystal binding: 4 | 5 | ```crystal 6 | require "yamlscript" 7 | 8 | # YAMLScript code 9 | ys_code = <<-YS 10 | !YS-v0 11 | inc: 41 12 | YS 13 | 14 | # Load and evaluate the YAMLScript 15 | result = YAMLScript.load(ys_code) 16 | puts "Result: #{result}" # Output: Result: 42 17 | 18 | # Regular YAML also works 19 | yaml_code = "foo: bar" 20 | result = YAMLScript.load(yaml_code) 21 | puts "YAML result: #{result["foo"]}" # Output: YAML result: bar 22 | ``` 23 | 24 | ## Development 25 | 26 | To build and run tests: 27 | 28 | ```bash 29 | # Clone the repository 30 | git clone https://github.com/yaml/yamlscript.git 31 | cd yamlscript/crystal 32 | 33 | # Build the binding and copy required libraries 34 | make build 35 | 36 | # Run the tests 37 | make test 38 | 39 | # Run the example 40 | make run-example 41 | ``` 42 | -------------------------------------------------------------------------------- /crystal/examples/simple.cr: -------------------------------------------------------------------------------- 1 | require "../src/yamlscript" 2 | 3 | # Simple YAMLScript example 4 | ys_simple = "!YS-v0\ninc: 41" 5 | 6 | # Try loading the YAMLScript 7 | begin 8 | result1 = YAMLScript.load(ys_simple) 9 | puts "Simple YAMLScript result: #{result1}" 10 | rescue ex : YAMLScript::Error 11 | puts "Error loading YAMLScript: #{ex.message}" 12 | end 13 | 14 | # Simple YAML example 15 | yaml_simple = "foo: bar" 16 | 17 | # Try loading plain YAML 18 | begin 19 | result2 = YAMLScript.load(yaml_simple) 20 | puts "Plain YAML result:" 21 | puts " foo: #{result2["foo"]}" 22 | rescue ex : YAMLScript::Error 23 | puts "Error loading YAML: #{ex.message}" 24 | end 25 | -------------------------------------------------------------------------------- /crystal/shard.yml: -------------------------------------------------------------------------------- 1 | name: yamlscript 2 | version: 0.1.96 3 | description: Program in YAML — Code is Data 4 | 5 | authors: 6 | - Josephine Pfeiffer 7 | - Ingy döt Net 8 | 9 | crystal: '>= 1.0.0' 10 | 11 | license: MIT 12 | repository: https://github.com/yaml/yamlscript-crystal 13 | -------------------------------------------------------------------------------- /crystal/spec/spec_helper.cr: -------------------------------------------------------------------------------- 1 | require "spec" 2 | require "../src/yamlscript" 3 | -------------------------------------------------------------------------------- /crystal/spec/yamlscript_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe YAMLScript do 4 | it "loads a basic YAMLScript" do 5 | result = YAMLScript.load("!YS-v0\ninc: 41") 6 | result.as_i.should eq(42) 7 | end 8 | 9 | it "loads plain YAML" do 10 | result = YAMLScript.load("foo: bar") 11 | result.as_h["foo"].as_s.should eq("bar") 12 | end 13 | 14 | it "raises an error on invalid YAMLScript" do 15 | expect_raises(Exception) do 16 | YAMLScript.load("!YS-v0\ninc: (41") 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /crystal/src/yamlscript/version.cr: -------------------------------------------------------------------------------- 1 | class YAMLScript 2 | VERSION = "0.1.96" 3 | end 4 | -------------------------------------------------------------------------------- /crystal/test/ffi.cr: -------------------------------------------------------------------------------- 1 | require "../src/yamlscript" 2 | 3 | # Test basic YAMLScript loading - returns a single value 4 | result = YAMLScript.load("!YS-v0\ninc: 41") 5 | if result.as_i != 42 6 | puts "Error: Expected 42, got #{result.inspect}" 7 | exit(1) 8 | end 9 | puts "Test 1 passed: Got 42 from inc: 41" 10 | 11 | # Test plain YAML loading - returns a hash 12 | result = YAMLScript.load("foo: bar") 13 | if !result.as_h.has_key?("foo") || result.as_h["foo"].as_s != "bar" 14 | puts "Error: Expected {\"foo\" => \"bar\"}, got #{result.inspect}" 15 | exit(1) 16 | end 17 | puts "Test 2 passed: Got {\"foo\" => \"bar\"} from plain YAML" 18 | 19 | puts "Crystal binding FFI test PASSED!" 20 | -------------------------------------------------------------------------------- /d/.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | __dummy.html 4 | docs/ 5 | /yamlscript 6 | yamlscript.so 7 | yamlscript.dylib 8 | yamlscript.dll 9 | yamlscript.a 10 | yamlscript.lib 11 | yamlscript-test-* 12 | *.exe 13 | *.o 14 | *.obj 15 | *.lst 16 | -------------------------------------------------------------------------------- /d/dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "ingy" 4 | ], 5 | "copyright": "Copyright 2022-2025, Ingy döt Net", 6 | "description": "Program in YAML — Code is Data", 7 | "license": "MIT", 8 | "name": "yamlscript" 9 | } 10 | -------------------------------------------------------------------------------- /d/source/app.d: -------------------------------------------------------------------------------- 1 | import std.stdio; 2 | 3 | void main() 4 | { 5 | writeln("YAMLScript for D coming soon."); 6 | } 7 | -------------------------------------------------------------------------------- /doc/capability.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Managing Capabilities 3 | talk: 0 4 | --- 5 | -------------------------------------------------------------------------------- /doc/chain.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Dot Chaining 3 | talk: 0 4 | --- 5 | 6 | One of the most powerful features of YS is the ability to chain function calls 7 | together. 8 | Functions are chained together using the `.` operator. 9 | 10 | Here are some examples: 11 | 12 | ```yaml 13 | x.5 # -> (nth x 5) 14 | x.abc # -> (get+ x 'abc) 15 | x.foo() # -> (foo x) 16 | x.foo(abc 123) # -> (foo x abc 123) 17 | x.foo(abc _ 123) # -> (foo abc x 123) 18 | x.foo(abc 123 _) # -> (foo abc 123 x) 19 | x.foo(_ _ _) # -> (foo x x x) 20 | x.? # -> (truey? x) 21 | x.! # -> (falsey? x) 22 | x.++ # -> (inc x) 23 | x.-- # -> (dec x) 24 | x.# # -> (count x) 25 | x.#? # -> (not (empty? x)) 26 | x.#! # -> (empty? x) 27 | x.#++ # -> (inc (count x)) 28 | x.#-- # -> (dec (count x)) 29 | x.@ # -> (deref x) 30 | x.> # -> (DBG x) 31 | x.abc.5.foo(22).#++ # -> (inc (count (foo (nth (get+ x 'abc) 5) 22))) 32 | x.>.abc.>.foo() # -> (foo (DBG (get+ (DBG x) 'abc))) 33 | ``` 34 | 35 | The `get+` looks up a key in a map (like the `get` function in Clojure) but 36 | given `x.y` looks for the string key `"y"` or the keyword `:y` or the symbol 37 | `'y` in the map `x`. 38 | 39 | Instead of needing to write `(:k y)` or `(get x "y")` or `(get x 'y)` depending 40 | on the type of the key, you can just write `x.y`. 41 | 42 | When `.` is used to call a function, the value of the LHS is passed as the first 43 | argument to the function on the RHS. 44 | When this is not the desired behavior, you can use `_` to indicate the position 45 | that the value should be passed as. 46 | 47 | Some core functions like `take` and `drop` (when called used the `.` operator) 48 | will automatically put the collection argument as the second argument. 49 | -------------------------------------------------------------------------------- /doc/cli.md: -------------------------------------------------------------------------------- 1 | one 2 | 3 | ```yaml 4 | 5 | foo: bar 6 | 7 | ``` 8 | two 9 | -------------------------------------------------------------------------------- /doc/clojure.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Clojure Basics 3 | talk: 0 4 | --- 5 | 6 | YS as a technology has many goals. 7 | YS as a programming language is essentially a different syntax for 8 | Clojure. 9 | However, YS is certainly not an attempt to replace Clojure. 10 | 11 | In theory YS could have been written in any language. 12 | But in reality, Clojure was the best choice for many reasons including: 13 | 14 | 1. Clojure is a Lisp and Lisps are "code as data". Since YS is YAML and YAML is 15 | data, Clojure is a natural fit. 16 | 2. GraalVM's native-image compiler and Clojure's SCI runtime make it possible to 17 | to use YS without Java or the JVM. 18 | 3. Clojure's core libraries are extensive, robust and well-documented. 19 | 20 | Since YS code always translates to Clojure code, it's important to have a good 21 | understanding of Clojure to write good YS code. 22 | 23 | Again, Clojure is a Lisp dialect. 24 | Lisps work entirely with parenthesized expressions containing a function 25 | followed by its arguments (S-Expressions). 26 | 27 | For example: 28 | 29 | ```clojure 30 | (+ 1 2 3) ; `+` is a function that adds its arguments 31 | (str "Hello " name "!") ; `str` is a function that concatenates its arguments 32 | (println (str "The answer is " (+ 2 3 7) "!")) ; Multiple nested expressions 33 | ``` 34 | 35 | The basic clojure syntactic forms are: 36 | 37 | * Lists - `(a b c)` 38 | * Vectors - `[a b c]` 39 | * Maps - `{a b, c d}` 40 | * Symbols - `a`, `b`, `c` 41 | * Quoted forms - `'(...)`, `'[...]`, `'{...}`, `'abc` 42 | * Strings - `"abc"` 43 | * Numbers - `123`, `3.14` 44 | * Characters - `\a`, `\b`, `\c` 45 | * Keywords - `:a`, `:b`, `:c` 46 | * Anonymous functions - `#(+ %1 %2)` 47 | * Sets - `#{a b c}` 48 | * Regex - `#"abc"` 49 | * Comments - `;` to end of line 50 | * Commented out forms - `#_(+ a b c)` 51 | 52 | See [Introduction to Clojure]( 53 | https://clojure-doc.org/articles/tutorials/introduction/) for more about 54 | Clojure. 55 | -------------------------------------------------------------------------------- /doc/common.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Common YS Functions 3 | talk: 0 4 | --- 5 | -------------------------------------------------------------------------------- /doc/define.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Defining Variables and Functions 3 | talk: 0 4 | --- 5 | 6 | Two of the most common things you'll want to do in YS code is to define 7 | variables and functions. 8 | 9 | It's very simple. 10 | Here's an example: 11 | 12 | ```yaml 13 | !YS-v0 14 | 15 | name =: 'world' 16 | 17 | defn main(): 18 | greeting =: 'Hello' 19 | say: "$greeting, $name!" 20 | ``` 21 | 22 | To define a variable with a value we specify a symbol name, followed by one or 23 | more spaces, followed by `=:` for the YS key (the LHS). 24 | The variable will be set to the result of the evaluation of the mapping pair's 25 | value (the RHS). 26 | 27 | To define a function we use `defn`, followed by the function name followed by 28 | the parenthesized arguments for the LHS. 29 | The RHS is the function body. 30 | 31 | Let's see how this compiles to Clojure internally using `ys -c file.ys`: 32 | 33 | ``` 34 | (def name "world") 35 | (defn main [] (let [greeting "Hello"] (say (str greeting ", " name "!")))) 36 | (apply main ARGS) 37 | ``` 38 | 39 | In our YS code we defined 2 variables: `name` and `greeting`. 40 | But in the Clojure code one became a `def` expression and the other used `let`. 41 | Using `=:` outside a function uses `def` and it's a file scope variable. 42 | Using `=:` inside a function uses `let` and the scope is the remainder of the 43 | function. 44 | 45 | This is idiomatic Clojure. 46 | -------------------------------------------------------------------------------- /doc/embedding.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Embedding YS in YAML 3 | talk: 0 4 | --- 5 | -------------------------------------------------------------------------------- /doc/env-vars.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Environment Vars 3 | talk: 0 4 | --- 5 | 6 | YS has a number of environment variables that can be set to control its 7 | behavior. 8 | These variables each begin with `YS_` and are all uppercase with underscores 9 | separating words. 10 | 11 | * `YSPATH` - A colon-separated list of directories to search for YS library 12 | files loaded with the `use` function. 13 | This is the only YS environment variable that doesn't start with `YS_`, but 14 | there is an equivalent `YS_PATH` that can be used instead. 15 | 16 | * `YS_PATH` - An alternative to `YSPATH` that is used if `YSPATH` is not set. 17 | 18 | * `YS_PRINT=1` - Same as `-p` (`--print`) command line option. 19 | 20 | * `YS_STREAM=1` - Same as `-s` (`--stream`) command line option. 21 | 22 | * `YS_OUTPUT=` - Same as `-o` (`--output=`) command line 23 | option. 24 | 25 | * `YS_FORMAT=` - Same as `-t` () 26 | 27 | * `YS_UNORDERED=1` - Same as `-u` (`--unordered`) command line option. 28 | 29 | * `YS_XTRACE=1` - Same as `-x` (`--xtrace`) command line option. 30 | 31 | * `YS_STACK_TRACE=1` - Same as `-S` (`--stack-trace`) command line option. 32 | 33 | * `YS_SHOW_OPTS=1` - Print all the option values. 34 | 35 | * `YS_SHOW_LEX=1` - Print the lexed tokens of each YS expression. 36 | 37 | * `YS_SHOW_INPUT=1` - Print the input YS expressions. 38 | -------------------------------------------------------------------------------- /doc/exercism.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Learn YS at Exercism 3 | talk: 0 4 | --- 5 | 6 | [Exercism](https://exercism.io) is a platform that offers code practice and 7 | mentorship for everyone. 8 | It is a great way to improve your coding skills and learn new programming 9 | languages. 10 | 11 | Exercism provides a series of exercises in over [70 programming languages]( 12 | https://exercism.io/tracks) including [YS / YAMLScript]( 13 | https://exercism.io/tracks/yamlscript) , and you can get feedback from mentors 14 | on your solutions. 15 | 16 | It is a fun and interactive way to learn to code, and it is completely free to 17 | use. 18 | If you are looking to improve your coding skills or learn a new language, 19 | Exercism is a good place to start. 20 | -------------------------------------------------------------------------------- /doc/ext-libs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using External Libraries 3 | talk: 0 4 | --- 5 | -------------------------------------------------------------------------------- /doc/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Welcome to the YS Documentation 3 | talk: 0 4 | --- 5 | 6 | YS is a still a fairly new language, and this documentation is a work in 7 | progress. 8 | 9 | While we hope that you find the information you came looking for here, we know 10 | that there are still many gaps in the documentation. 11 | 12 | The good news is **"You Can Help!"**. 13 | 14 | Writing great documentation is a team effort, and we are trying to make it as 15 | easy as possible for you to contribute. 16 | 17 | Almost every page on this site (including this one!!) has an **"Edit this 18 | page"** button at the top: 19 | 20 | ![Edit this page image]( 21 | https://github.com/user-attachments/assets/f2ee58c3-d5e5-4282-ac6d-d134e4ce6e1f) 22 | 23 | As you read the documentation, if you find a typo or something that is unclear, 24 | you can click the "Edit this page" button, make the changes, and submit a pull 25 | request. 26 | 27 | Furthermore, most pages (and all the documentation pages) have a **"Discuss this 28 | page"** button at the top: 29 | 30 | ![Discuss this page image]( 31 | https://github.com/user-attachments/assets/83a204d6-14ac-4210-a276-a8cb9dc0dfe7) 32 | 33 | If you have ideas on how to improve the page or have questions about the 34 | content, this will take you to a [YS GitHub Discussions]( 35 | https://github.com/yaml/yamlscript/discussions) discussion about the page (or to 36 | instructions on how to start a new discussion for a page that doesn't have one 37 | yet). 38 | 39 | We look forward to this YS journey together and hope that you will help us make 40 | the documentation the best it can be! 41 | -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introducing YS 3 | talk: 0 4 | --- 5 | 6 | YS is a new approach to providing the extra capabilities that YAML users have 7 | been asking for (or adding themselves) for years. 8 | YS embeds cleanly into existing YAML files and adds new capabilities such as: 9 | 10 | * Getting data from other YAML files 11 | * Assigning variables 12 | * Referencing other parts of YAML (without anchorsi/aliases) 13 | * Interpolating variables and function calls into strings 14 | * Transforming data structures 15 | * Defining and calling functions 16 | * Using external libraries 17 | * Running shell commands 18 | * And much more... 19 | 20 | All of YS is (and must be) valid YAML syntax, even though it might seem 21 | surprising from time to time. 22 | Also all YAML config files are valid YS files and YS will treat them as such (no 23 | code execution), unless you explicitly tell it to do more (by adding a `!YS-v0` 24 | tag to the start). 25 | 26 | ```yaml 27 | !YS-v0 28 | say: "Welcome to YS!" 29 | ``` 30 | 31 | YS is also a complete, mature, functional, performant programming language. 32 | That's because under the hood, YS code is compiled to [Clojure]( 33 | https://clojure.org/) code and evaluated by a Clojure runtime. 34 | For most day to day YS use, you won't need to know anything about Clojure, but 35 | when you need to do something more advanced, [all of Clojure]( 36 | https://clojuredocs.org/) is available for you to use. 37 | 38 | Even though Clojure is a Lisp, YS code looks a lot more like Python, Ruby, Perl 39 | or JavaScript. 40 | And even though Clojure is a JVM (Java) language, YS doesn't use the JVM at all. 41 | YS is a fast standalone native binary, as is the `libyamlscript` shared library 42 | that it is used by all [YS loader libraries](loaders.md). 43 | -------------------------------------------------------------------------------- /doc/loaders.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Loader Libraries 3 | talk: 0 4 | --- 5 | 6 | YS is focused on providing a loader library for every programming language 7 | where YAML is used. 8 | Ideally it should be a drop-in replacement for the existing YAML loader library 9 | you are using. 10 | 11 | All existing YAML config files are already valid YS files and using the YS 12 | loader to load them should work without any changes. 13 | The advantage of using the YS loader is that they all work the same way and 14 | provide the same capabilities, regardless of the underlying programming 15 | language. 16 | 17 | The following loader libraries are currently available: 18 | 19 | * [Clojure](https://clojars.org/org.yamlscript/clj-yamlscript) 20 | * [Go](https://github.com/yaml/yamlscript-go) 21 | * [Java](https://clojars.org/org.yamlscript/yamlscript) 22 | * [Julia](https://juliahub.com/ui/Packages/General/YAMLScript) 23 | * [NodeJS](https://www.npmjs.com/package/@yaml/yamlscript) 24 | * [Perl](https://metacpan.org/dist/YAMLScript/view/lib/YAMLScript.pod) 25 | * [Python](https://pypi.org/project/yamlscript/) 26 | * [Raku](https://raku.land/zef:ingy/YAMLScript) 27 | * [Ruby](https://rubygems.org/search?query=yamlscript) 28 | * [Rust](https://crates.io/crates/yamlscript) 29 | -------------------------------------------------------------------------------- /doc/macros.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Macros 3 | talk: 0 4 | --- 5 | -------------------------------------------------------------------------------- /doc/mdys.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn mdys-fmt-fns(o): 4 | str "\n": 5 | fmt-fns: o 6 | 7 | defn fmt-fns(body): 8 | reduce-kv _ '' body: 9 | fn(md fn-sig desc): 10 | sig =: fn-sig.replace(/\) / ') → ') 11 | desc =: 12 | desc.has?(\\|).if("$desc\n" desc) 13 | .replace(/\b(C[CDS])\/(\S+)/ clojure-docs-link) 14 | md +: | 15 | * `$sig` — $(desc.replace(/\| / "\n\n ")) 16 | 17 | defn clojure-docs-link([_ type name]): 18 | func =: name.replace(/\?$/ '_q') 19 | cond: 20 | type == 'CC': 21 | "[`clojure.core/$name`](https://clojuredocs.org/clojure.core/$func)" 22 | type == 'CD': 23 | "[`clojure.data/$name`](https://clojuredocs.org/clojure.data/$func)" 24 | type == 'CS': 25 | "[`clojure.string/$name`](https://clojuredocs.org/clojure.string/$func)" 26 | 27 | defn mdys-quick-ref(o): 28 | links =: 29 | join ', ': 30 | for name words(o): 31 | "[$name](https://clojuredocs.org/clojure.core/$name)" 32 | 33 | =>: |+ 34 | Clojure Core: 35 | 36 | * $links 37 | 38 | # vim: ft=yaml sw=2 lisp: 39 | -------------------------------------------------------------------------------- /doc/multi-doc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS in Files with Multiple YAML Documents 3 | talk: 0 4 | --- 5 | -------------------------------------------------------------------------------- /doc/programming.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Programming Language 3 | talk: 0 4 | --- 5 | 6 | -------------------------------------------------------------------------------- /doc/referencing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Referencing YAML Nodes 3 | talk: 0 4 | --- 5 | 6 | One thing that's important when adding code to YAML is having ways for the code 7 | to reference other data. 8 | -------------------------------------------------------------------------------- /doc/schema.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS and YAML Schemas 3 | talk: 0 4 | --- 5 | -------------------------------------------------------------------------------- /doc/templating.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Templating with YS 3 | talk: 0 4 | --- 5 | 6 | -------------------------------------------------------------------------------- /doc/ys-clj.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Replaced Clojure Functions 3 | talk: 0 4 | --- 5 | 6 | A number of standard functions from Clojure's standard library `clojure::core` 7 | have been replaced by functions in the `ys::std` library. 8 | In general the replacements have the same intent as the original functions, but 9 | from a YS perspective. 10 | 11 | When you absolutely need the original Clojure functions, they are available in 12 | this `ys::clj` library. 13 | These functions are automatically available in YAMLSCript by using the `clj/` 14 | prefix. 15 | 16 | 17 | ## Functions 18 | 19 | The documentation for these functions is available in the Clojure documentation 20 | web site, so we include a link to there in each definition. 21 | 22 | 23 | * `clj/compile` — [In Clojure](https://clojuredocs.org/clojure.core/compile) the 24 | `compile` function compiles a namespace into a set of class files. 25 | In YS it converts a YS source code string into a 26 | Clojure source code string. 27 | 28 | * `clj/load` — [In Clojure](https://clojuredocs.org/clojure.core/load) the 29 | `load` function loads a file from the classpath. 30 | In YS it's an alias for `load-file`(below). 31 | 32 | * `clj/load-file` — [In Clojure](https://clojuredocs.org/clojure.core/load-file) 33 | the `load-file` function loads a Clojure file from a given file path. 34 | In YS it loads a YS file from a given file path. 35 | 36 | * `clj/num` — [In Clojure](https://clojuredocs.org/clojure.core/num) the `num` 37 | function converts a Java number to a Clojure number. 38 | In YS it converts a numeric string to a number. 39 | 40 | * `clj/use` — [In Clojure](https://clojuredocs.org/clojure.core/use) the `use` 41 | function is used to refer a namespace into the current namespace. 42 | In YS it loads a YS or Clojure library from `YSPATH`. 43 | -------------------------------------------------------------------------------- /doc/ys-csv.mdys: -------------------------------------------------------------------------------- 1 | --- 2 | title: CSV and TSV 3 | talk: 0 4 | edit: doc/ys-csv.mdys 5 | --- 6 | 7 | 8 | This library provides functions for reading and writing the [CSV]( 9 | https://en.wikipedia.org/wiki/Comma-separated_values) and [TSV]( 10 | https://en.wikipedia.org/wiki/Tab-separated_values) formats. 11 | 12 | ```mdys:fmt-fns 13 | read(S): Short name for `csv/read-csv(S)` 14 | 15 | read-csv(s): Convert a CSV string to a list of lists 16 | 17 | read-tsv(s): Convert a TSV string to a list of lists 18 | 19 | write(S): Short name for `csv/write-csv(S)` 20 | 21 | write-csv(LoL): Convert a list of lists to a CSV string | 22 | 23 | write-tsv(LoL): Convert a list of lists to a TSV string 24 | ``` 25 | -------------------------------------------------------------------------------- /doc/ys-json.mdys: -------------------------------------------------------------------------------- 1 | --- 2 | title: JSON Library 3 | talk: 0 4 | edit: doc/ys-json.mdys 5 | --- 6 | 7 | 8 | ```mdys:fmt-fns 9 | load(S): Load a JSON string to a native data structure. 10 | 11 | dump(X): Dump a native data structure to a JSON string. 12 | 13 | pretty(X): Dump a native data structure to a pretty JSON string. 14 | ``` 15 | -------------------------------------------------------------------------------- /doc/ys-libs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Builtin Libraries 3 | talk: 0 4 | --- 5 | 6 | * [`ys::clj`](ys-clj.md) — Original Clojure functions replaced by [`ys::std`]( 7 | ys-std.md) 8 | * [`ys::json`](ys-json.md) — JSON load and dump functions 9 | * [`ys::std`](ys-std.md) — YS standard library 10 | * [`ys::taptest`](ys-taptest.md) — TAP Test library 11 | * [`ys::yaml`](ys-yaml.md) — YAML load and dump functions 12 | * [`ys::ys`](ys-ys.md) — Using YS in YS 13 | -------------------------------------------------------------------------------- /doc/ys-yaml.mdys: -------------------------------------------------------------------------------- 1 | --- 2 | title: YAML Library 3 | talk: 0 4 | edit: doc/ys-yaml.mdys 5 | --- 6 | 7 | 8 | ```mdys:fmt-fns 9 | load(S): Load a YAML string to a native data structure. 10 | 11 | load-all(S): Load a YAML string into a list of document nodes. 12 | 13 | dump(X): Dump a native data structure to a YAML string. 14 | 15 | dump-all(V): Dump an array of native data structures to a multi-document YAML 16 | string. 17 | ``` 18 | -------------------------------------------------------------------------------- /doc/ys-ys.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Internals Library 3 | talk: 0 4 | --- 5 | 6 | This library serves 2 purposes. 7 | It provides functions for working with YS code from within a YS program/file. 8 | 9 | It also provides functions that are wrappers around common Clojure functions so 10 | that they can be used in places where functions are not allowed; like in [dot 11 | chaining operations](chain.md). 12 | 13 | You can use these functions with the `ys/` (or `ys::ys/`) prefix. 14 | 15 | 16 | ## YS Functions 17 | 18 | * `compile` — Compile a YS string to a Clojure string 19 | 20 | * `eval` — Evaluate a YS string 21 | 22 | * `load-file` — Load a YS file path 23 | 24 | * `load-pod` — Load a Babashka Pod 25 | 26 | * `unload-pods` — Unload all loaded pods 27 | 28 | * `use` — Use a YS or Clojure library found in `YSPATH`. 29 | Normally called as `use`, not `ys/use`. 30 | 31 | 32 | ## Macro Wrapper Functions 33 | 34 | * `for` — An eager version of Clojure's lazy `for` macro 35 | * `if` — Wrapper around the Clojure `if` special form 36 | * `when` — Wrapper around the Clojure `when` macro 37 | -------------------------------------------------------------------------------- /elixir/.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /elixir/.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | /_build/ 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | yamlscript-*.tar 24 | 25 | # Temporary files, for example, from tests. 26 | /tmp/ 27 | -------------------------------------------------------------------------------- /elixir/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | 3 | default: 4 | 5 | build: _build 6 | 7 | publish: build 8 | mix hex.publish 9 | 10 | clean: 11 | $(RM) -r _build deps doc 12 | $(RM) yamlscript-*.tar 13 | 14 | _build: deps 15 | mix hex.build 16 | 17 | deps: 18 | mix deps.get 19 | -------------------------------------------------------------------------------- /elixir/README.md: -------------------------------------------------------------------------------- 1 | YAMLScript 2 | ========== 3 | 4 | Program in YAML — Code is Data 5 | 6 | 7 | ## Synopsis 8 | 9 | A YAMLScript program `greet.ys` to greet someone 6 times: 10 | ``` 11 | #!/usr/bin/env yamlscript 12 | 13 | defn main(name): 14 | say: "Hello, $name!" 15 | ``` 16 | 17 | Run: 18 | ``` 19 | $ yamlscript greet.ys YAMLScript 20 | Hello, YAMLScript! 21 | ``` 22 | 23 | 24 | ## Status 25 | 26 | This is very ALPHA software. 27 | 28 | 29 | ## Authors 30 | 31 | * [Ingy döt Net](https://github.com/ingydotnet) 32 | 33 | 34 | ## Copyright and License 35 | 36 | Copyright 2022-2025 by Ingy döt Net 37 | 38 | This is free software, licensed under: 39 | 40 | The MIT (X11) License 41 | -------------------------------------------------------------------------------- /elixir/lib/yamlscript.ex: -------------------------------------------------------------------------------- 1 | defmodule Yamlscript do 2 | @moduledoc """ 3 | Documentation for `Yamlscript`. 4 | """ 5 | 6 | @doc """ 7 | Hello world. 8 | 9 | ## Examples 10 | 11 | iex> Yamlscript.hello() 12 | :world 13 | 14 | """ 15 | def hello do 16 | :world 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /elixir/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Yamlscript.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :yamlscript, 7 | version: "0.0.16", 8 | description: "Program in YAML — Code is Data", 9 | elixir: "~> 1.12", 10 | package: package(), 11 | deps: deps() 12 | ] 13 | end 14 | 15 | def package do 16 | [ 17 | licenses: ["MIT"], 18 | files: ~w(lib test mix.exs README*), 19 | maintainers: ["Ingy döt Net "], 20 | links: %{"GitHub" => "https://github.com/yaml/yamlscript"} 21 | ] 22 | end 23 | 24 | defp deps do 25 | [ 26 | {:ex_doc, ">= 0.0.0", only: :dev, runtime: false} 27 | ] 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /elixir/mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"}, 3 | "ex_doc": {:hex, :ex_doc, "0.28.4", "001a0ea6beac2f810f1abc3dbf4b123e9593eaa5f00dd13ded024eae7c523298", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bf85d003dd34911d89c8ddb8bda1a958af3471a274a4c2150a9c01c78ac3f8ed"}, 4 | "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, 5 | "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, 6 | "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, 7 | "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, 8 | } 9 | -------------------------------------------------------------------------------- /elixir/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /elixir/test/yamlscript_test.exs: -------------------------------------------------------------------------------- 1 | defmodule YamlscriptTest do 2 | use ExUnit.Case 3 | doctest Yamlscript 4 | 5 | test "greets the world" do 6 | assert Yamlscript.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /go/.gitignore: -------------------------------------------------------------------------------- 1 | /go/ 2 | /yamlscript-go/ 3 | -------------------------------------------------------------------------------- /go/README: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | To install the Go binding run `make -C go install`. 4 | 5 | You can then run `go get github.com/yaml/yamlscript/go/ys` and make use of the 6 | `ys.Load` function. 7 | 8 | 9 | # Testing 10 | 11 | This needs to work: 12 | 13 | ``` 14 | $ make -C go test 15 | ``` 16 | -------------------------------------------------------------------------------- /go/doc/authors.md: -------------------------------------------------------------------------------- 1 | * [Ingy döt Net](https://github.com/ingydotnet) 2 | * [Andrew Pam](https://github.com/xanni) 3 | -------------------------------------------------------------------------------- /go/doc/readme.md: -------------------------------------------------------------------------------- 1 | ## Go Usage 2 | 3 | In `go.mod`: 4 | 5 | ```go 6 | require github.com/yaml/yamlscript-go v0.1.96 7 | ``` 8 | 9 | File `prog.go`: 10 | 11 | ```go 12 | package main 13 | package main 14 | 15 | import ( 16 | "fmt" 17 | "github.com/yaml/yamlscript-go" 18 | ) 19 | 20 | func main() { 21 | data, err := yamlscript.Load("a: [b, c]") 22 | if err != nil { 23 | return 24 | } 25 | fmt.Println(data) 26 | } 27 | ``` 28 | 29 | 30 | 31 | ## Installation 32 | 33 | You can install this module like any other Go module: 34 | 35 | ```bash 36 | $ go get github.com/yaml/yamlscript-go@v0.1.96 37 | ``` 38 | 39 | but you will need to have a system install of `libyamlscript.so`. 40 | 41 | One simple way to do that is with: 42 | 43 | ```bash 44 | $ curl https://yamlscript.org/install | bash 45 | ``` 46 | 47 | > Note: The above command will install the latest version of the YAMLScript 48 | command line utility, `ys`, and the shared library, `libyamlscript.so`, into 49 | `~/local/bin` and `~/.local/lib` respectively. 50 | 51 | See for more info. 52 | 53 | 54 | ### Environment Variables 55 | 56 | At the current time, you will need to set 3 environment variables to use the 57 | module: 58 | 59 | ```bash 60 | export CGO_CFLAGS="-I $HOME/.local/include" 61 | export CGO_LDFLAGS="-L $HOME/.local/lib" 62 | export LD_LIBRARY_PATH="$HOME/.local/lib" 63 | ``` 64 | -------------------------------------------------------------------------------- /go/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/yaml/yamlscript/go 2 | 3 | go 1.22.2 4 | 5 | require github.com/stretchr/testify v1.9.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /go/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 6 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /go/yamlscript.go: -------------------------------------------------------------------------------- 1 | package yamlscript 2 | 3 | // #cgo LDFLAGS: -lyamlscript.0.1.96 4 | // #include 5 | // #include 6 | import "C" 7 | import ( 8 | "encoding/json" 9 | "errors" 10 | "log" 11 | "runtime" 12 | "unsafe" 13 | ) 14 | 15 | // Create a new GraalVM isolatethread for life of the YAMLScript instance: 16 | var isolatethread unsafe.Pointer 17 | 18 | // Tear down the isolate thread to free resources 19 | func free() { 20 | rc := C.graal_tear_down_isolate((*C.graal_isolatethread_t)(isolatethread)) 21 | if rc != 0 { 22 | log.Fatal("Failed to tear down isolate") 23 | } 24 | } 25 | 26 | // YAMLScript instance constructor 27 | func init() { 28 | rc := C.graal_create_isolate(nil, nil, (**C.graal_isolatethread_t)(unsafe.Pointer(&isolatethread))) 29 | if rc != 0 { 30 | log.Fatal("Failed to create isolate") 31 | } 32 | runtime.SetFinalizer(&isolatethread, free) 33 | } 34 | 35 | // Compile and eval a YAMLScript string and return the result 36 | func Load(input string) (data any, err error) { 37 | cs := C.CString(input) 38 | 39 | // Call 'load_ys_to_json' function in libyamlscript shared library: 40 | data_json := C.GoString(C.load_ys_to_json(C.longlong(uintptr(isolatethread)), cs)) 41 | C.free(unsafe.Pointer(cs)) 42 | 43 | // Decode the JSON response: 44 | var resp map[string]any 45 | err = json.Unmarshal([]byte(data_json), &resp) 46 | if err != nil { 47 | return 48 | } 49 | 50 | // Check for libyamlscript error in JSON response: 51 | if error_json, ok := resp["error"]; ok { 52 | err = errors.New(error_json.(map[string]any)["cause"].(string)) 53 | return 54 | } 55 | 56 | // Get the response object from evaluating the YAMLScript string: 57 | var ok bool 58 | if data, ok = resp["data"]; !ok { 59 | err = errors.New("unexpected response from 'libyamlscript'") 60 | } 61 | 62 | return 63 | } 64 | -------------------------------------------------------------------------------- /go/yamlscript_test.go: -------------------------------------------------------------------------------- 1 | package yamlscript_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/yaml/yamlscript/go" 8 | ) 9 | 10 | func TestYamlScript(t *testing.T) { 11 | _, err := yamlscript.Load(":") 12 | assert.Error(t, err) 13 | 14 | data, err := yamlscript.Load("!YS-v0:\ntest:: inc(41)") 15 | assert.NoError(t, err) 16 | assert.Equal(t, map[string]any{"test": (float64)(42)}, data) 17 | } 18 | -------------------------------------------------------------------------------- /java/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | include $(COMMON)/java.mk 4 | 5 | YAMLSCRIPT_JAVA_JAR := target/yamlscript-0.1.96.jar 6 | 7 | MVN_COMMANDS := \ 8 | compile \ 9 | install \ 10 | package \ 11 | test \ 12 | validate \ 13 | 14 | #------------------------------------------------------------------------------ 15 | 16 | $(MVN_COMMANDS):: $(JAVA_INSTALLED) $(LIBYS_SO_FQNP) 17 | mvn $@ 18 | 19 | release: $(JAVA_INSTALLED) $(LIBYS_SO_FQNP) test package 20 | ifndef n 21 | $(error 'make $@' needs the n variable set to the new version) 22 | endif 23 | mvn deploy:deploy-file \ 24 | -s ~/.mvn-user-settings.xml \ 25 | -Dfile=$(YAMLSCRIPT_JAVA_JAR) \ 26 | -DpomFile=pom.xml \ 27 | -DrepositoryId=clojars \ 28 | -Durl=https://clojars.org/repo/ 29 | 30 | clean:: 31 | $(RM) -r reports/ target/ 32 | -------------------------------------------------------------------------------- /java/src/main/java/org/yamlscript/yamlscript/ILibYAMLScript.java: -------------------------------------------------------------------------------- 1 | package org.yamlscript.yamlscript; 2 | 3 | import com.sun.jna.Library; 4 | import com.sun.jna.Pointer; 5 | import com.sun.jna.ptr.PointerByReference; 6 | 7 | public interface ILibYAMLScript extends Library { 8 | int graal_create_isolate(Pointer params, PointerByReference isolate, PointerByReference thread); 9 | int graal_tear_down_isolate(Pointer thread); 10 | String load_ys_to_json(Pointer thread, String yamlscript); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /java/src/site/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | yamlscript 7 | https://maven.apache.org/images/apache-maven-project.png 8 | https://www.apache.org/ 9 | 10 | 11 | 12 | https://maven.apache.org/images/maven-logo-black-on-white.png 13 | https://maven.apache.org/ 14 | 15 | 16 | 17 | org.apache.maven.skins 18 | maven-fluido-skin 19 | 1.7 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /julia/.gitignore: -------------------------------------------------------------------------------- 1 | /Manifest.toml 2 | -------------------------------------------------------------------------------- /julia/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2025 Ingy döt Net and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /julia/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | 4 | JULIA := $(shell command -v julia) 5 | 6 | HEAD_COMMIT := $(shell git rev-parse HEAD) 7 | 8 | #------------------------------------------------------------------------------ 9 | build:: build-doc 10 | 11 | build-doc:: ReadMe.md 12 | 13 | ifdef JULIA 14 | test:: $(LIBYS_SO_FQNP) deps 15 | $(JULIA) --project=. test/runtests.jl 16 | 17 | deps:: 18 | $(JULIA) --project=. -e 'using Pkg; Pkg.add("JSON")' 19 | 20 | release: 21 | ifndef YS_GH_TOKEN 22 | $(error YS_GH_TOKEN not found) 23 | endif 24 | $(call need-curl) 25 | curl -L -X POST \ 26 | -H "Accept: application/vnd.github+json" \ 27 | -H "Authorization: Bearer $(YS_GH_TOKEN)" \ 28 | -H "X-GitHub-Api-Version: 2022-11-28" \ 29 | $(YS_GH_API_URL)/commits/$(HEAD_COMMIT)/comments \ 30 | -d '{"body":"@JuliaRegistrator register subdir=julia\n"}' 31 | 32 | repl: 33 | $(JULIA) --project=. 34 | endif 35 | 36 | clean:: 37 | $(RM) Manifest.toml 38 | -------------------------------------------------------------------------------- /julia/Project.toml: -------------------------------------------------------------------------------- 1 | name = "YAMLScript" 2 | uuid = "c6519b1f-f61a-46f8-9c82-37138c212585" 3 | authors = ["Ingy döt Net "] 4 | version = "0.1.96" 5 | 6 | [deps] 7 | JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 8 | 9 | [compat] 10 | julia = "1" 11 | JSON = "0.21.4" 12 | 13 | [extras] 14 | Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 15 | 16 | [targets] 17 | test = ["Test"] 18 | -------------------------------------------------------------------------------- /julia/bin/ys-yamlscript.jl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # https://docs.julialang.org/en/v1/manual/faq/#How-do-I-pass-options-to-julia-using-#!/usr/bin/env? 4 | #= 5 | exec julia --project=. --color=yes --startup-file=no -e 'include(popfirst!(ARGS))' \ 6 | "${BASH_SOURCE[0]}" "$@" 7 | =# 8 | 9 | using YAMLScript 10 | 11 | file = popfirst!(ARGS) 12 | 13 | YAMLScript.new().fromFile(file).run(ARGS) 14 | 15 | # vim: ft=julia: 16 | -------------------------------------------------------------------------------- /julia/doc/authors.md: -------------------------------------------------------------------------------- 1 | * [Ingy döt Net](https://github.com/ingydotnet) 2 | * [Kenta Murata](https://github.com/mrkn) 3 | -------------------------------------------------------------------------------- /julia/doc/readme.md: -------------------------------------------------------------------------------- 1 | ## Julia Usage 2 | 3 | File `prog.jl`: 4 | 5 | ```julia 6 | import YAMLScript as YS 7 | ys = YS.Runtime() 8 | yaml = read("file.ys", String) 9 | data = YS.load(ys, yaml) 10 | println(data) 11 | ``` 12 | 13 | File `file.ys`: 14 | 15 | ```yaml 16 | !YS-v0: 17 | 18 | name =: "World" 19 | 20 | foo: [1, 2, ! inc(41)] 21 | bar:: load("other.yaml") 22 | baz:: "Hello, $name!" 23 | ``` 24 | 25 | File `other.yaml`: 26 | 27 | ```yaml 28 | oh: Hello 29 | ``` 30 | 31 | Run: 32 | 33 | ```text 34 | $ julia prog.jl 35 | Dict{String, Any}("bar" => Dict{String, Any}("oh" => "Hello"), "baz" => "Hello, World!", "foo" => Any[1, 2, 42]) 36 | ``` 37 | 38 | 39 | ## Installation 40 | 41 | You can install this package like any other Julia package: 42 | 43 | ```bash 44 | $ julia --project=. -e 'using Pkg; Pkg.add("YAMLScript")' 45 | ``` 46 | 47 | but you will need to have a system install of `libyamlscript.so`. 48 | 49 | One simple way to do that is with: 50 | 51 | ```bash 52 | $ curl https://yamlscript.org/install | bash 53 | ``` 54 | 55 | > Note: The above command will install the latest version of the YAMLScript 56 | command line utility, `ys`, and the shared library, `libyamlscript.so`, into 57 | `~/local/bin` and `~/.local/lib` respectively. 58 | You may need to add this install directory to `LD_LIBRARY_PATH`. 59 | 60 | See for more info. 61 | -------------------------------------------------------------------------------- /julia/etc/ReadMe.md: -------------------------------------------------------------------------------- 1 | julia/etc 2 | ========= 3 | 4 | The GHA workflow file here will be used later when we implement workflows for 5 | everything. 6 | -------------------------------------------------------------------------------- /julia/src/Function.jl: -------------------------------------------------------------------------------- 1 | function val(str, ns) 2 | if typeof(str) != String 3 | return str 4 | end 5 | 6 | if !occursin(r"\$", str) 7 | return str 8 | end 9 | 10 | return replace(str, r"\$(\w+)" => 11 | function(m) return ns[m[2:end]] end 12 | ) 13 | end 14 | 15 | mutable struct Func 16 | name 17 | sign 18 | body 19 | 20 | call 21 | 22 | function Func(name, sign, body) 23 | this = new() 24 | 25 | this.name = name 26 | this.sign = sign 27 | this.body = body 28 | 29 | this.call = function(ns, args) 30 | i = 1 31 | for var in this.sign 32 | ns[var] = args[i] 33 | i += 1 34 | end 35 | 36 | for stmt in this.body 37 | f = ns[collect(keys(stmt))[1]] 38 | v = collect(values(stmt))[1] 39 | f(val(v, ns)) 40 | end 41 | end 42 | 43 | return this 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /julia/src/YAMLScript.jl: -------------------------------------------------------------------------------- 1 | module YAMLScript 2 | 3 | import JSON 4 | 5 | include("libyamlscript.jl") 6 | 7 | mutable struct Runtime 8 | isolate::Ref{Ptr{Cvoid}} 9 | error 10 | 11 | function Runtime() 12 | ys = new(Ref{Ptr{Cvoid}}(), nothing) 13 | ys.isolate[] = C_NULL 14 | return ys 15 | end 16 | end 17 | 18 | function graal_create_isolate(func::Function, params, isolate::Ref{Ptr{Cvoid}}, thread::Ref{Ptr{Cvoid}}) 19 | libyamlscript.init() 20 | if libyamlscript.graal_create_isolate(params, isolate, thread) != 0 21 | error("Failed to create isolate") 22 | end 23 | try 24 | return func() 25 | finally 26 | if libyamlscript.graal_tear_down_isolate(thread[]) != 0 27 | error("Failed to tear down isolate") 28 | end 29 | end 30 | end 31 | 32 | function load(ys::Runtime, code::AbstractString) 33 | thread = Ref{Ptr{Cvoid}}() 34 | thread[] = C_NULL 35 | 36 | graal_create_isolate(C_NULL, ys.isolate, thread) do 37 | json_data = libyamlscript.load_ys_to_json(thread[], code) 38 | json_src = unsafe_string(json_data) 39 | resp = JSON.parse(json_src) 40 | ys.error = get(resp, "error", nothing) 41 | if ys.error !== nothing 42 | error(get(ys.error, "cause", "")) 43 | end 44 | if haskey(resp, "data") 45 | return resp["data"] 46 | else 47 | error("Unexpected response from 'libyamlscript'") 48 | end 49 | end 50 | end 51 | 52 | end 53 | -------------------------------------------------------------------------------- /julia/src/libyamlscript.jl: -------------------------------------------------------------------------------- 1 | module libyamlscript 2 | 3 | import Base.Libc: Libdl 4 | 5 | const YAMLSCRIPT_VERSION = "0.1.96" 6 | const libyamlscript_name = "libyamlscript.$(Libdl.dlext).$(YAMLSCRIPT_VERSION)" 7 | const libhandle = Ref{Ptr{Cvoid}}() 8 | const graal_create_isolate_fptr = Ref{Ptr{Cvoid}}() 9 | const graal_tear_down_isolate_fptr = Ref{Ptr{Cvoid}}() 10 | const load_ys_to_json_fptr = Ref{Ptr{Cvoid}}() 11 | 12 | function graal_create_isolate(params, isolate, thread) 13 | ccall(graal_create_isolate_fptr[], 14 | Cint, (Ptr{Cvoid}, Ptr{Ptr{Cvoid}}, Ptr{Ptr{Cvoid}}), 15 | params, isolate, thread) 16 | end 17 | 18 | function graal_tear_down_isolate(thread) 19 | ccall(graal_tear_down_isolate_fptr[], Cint, (Ptr{Cvoid},), thread) 20 | end 21 | 22 | function load_ys_to_json(thread, script::String) 23 | ccall(load_ys_to_json_fptr[], Cstring, (Ptr{Cvoid}, Cstring), thread, script) 24 | end 25 | 26 | function _library_not_found_error(libname) 27 | msg = """ 28 | Shared library file `$(libname)` not found 29 | Try: curl https://yamlscript.org/install | VERSION=$(YAMLSCRIPT_VERSION) LIB=1 bash 30 | See: https://github.com/yaml/yamlscript/wiki/Installing-YAMLScript""" 31 | error(msg) 32 | end 33 | 34 | function init() 35 | libpath = Libdl.find_library(libyamlscript_name) 36 | if libpath == "" 37 | _library_not_found_error(libyamlscript_name) 38 | end 39 | 40 | libhandle[] = Libdl.dlopen(libpath, Libdl.RTLD_LAZY | Libdl.RTLD_LOCAL) 41 | graal_create_isolate_fptr[] = Libdl.dlsym(libhandle[], :graal_create_isolate) 42 | graal_tear_down_isolate_fptr[] = Libdl.dlsym(libhandle[], :graal_tear_down_isolate) 43 | load_ys_to_json_fptr[] = Libdl.dlsym(libhandle[], :load_ys_to_json) 44 | end 45 | 46 | end # module libyamlscript 47 | -------------------------------------------------------------------------------- /julia/test/runtests.jl: -------------------------------------------------------------------------------- 1 | module TestYAMLScript 2 | 3 | using Test 4 | import YAMLScript as YS 5 | 6 | @testset "load" begin 7 | function load(script) 8 | ys = YS.Runtime() 9 | YS.load(ys, script) 10 | end 11 | 12 | @testset "a: 1" begin 13 | data = load("a: 1") 14 | @test data["a"] == 1 15 | end 16 | 17 | @testset "A simple script" begin 18 | script = """ 19 | !YS-v0: 20 | say: "Hello" 21 | key:: inc(42) 22 | baz:: range(1 6) 23 | """ 24 | obj = load(script) 25 | @test haskey(obj, "say") 26 | @test haskey(obj, "key") 27 | @test haskey(obj, "baz") 28 | 29 | @test obj["say"] == "Hello" 30 | @test obj["key"] == 43 31 | @test obj["baz"] == [1, 2, 3, 4, 5] 32 | end 33 | 34 | # @testset "An error case" begin 35 | # script = """ 36 | # !YS-v0: 37 | # : : : : : : 38 | # """ 39 | # @test_throws Exception load(script) 40 | # end 41 | 42 | @testset "Load multiple times" begin 43 | script = """ 44 | !YS-v0: 45 | say: "Hello" 46 | key:: inc(42) 47 | baz:: range(1 6) 48 | """ 49 | ys = YS.Runtime() 50 | obj = YS.load(ys, script) 51 | @test obj["say"] == "Hello" 52 | @test obj["key"] == 43 53 | @test obj["baz"] == [1, 2, 3, 4, 5] 54 | obj = YS.load(ys, script) 55 | @test obj["say"] == "Hello" 56 | @test obj["key"] == 43 57 | @test obj["baz"] == [1, 2, 3, 4, 5] 58 | end 59 | end 60 | 61 | end # module TestYAMLScript 62 | -------------------------------------------------------------------------------- /libyamlscript/.gitignore: -------------------------------------------------------------------------------- 1 | /src/libyamlscript/Core.class 2 | /lib/ 3 | -------------------------------------------------------------------------------- /libyamlscript/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/java.mk 3 | include $(COMMON)/clojure.mk 4 | include $(COMMON)/native.mk 5 | include $(COMMON)/vars-core.mk 6 | include $(COMMON)/vars-libys.mk 7 | 8 | #------------------------------------------------------------------------------ 9 | build:: $(LIBYS_DEPS) 10 | 11 | # jar: $(LIBYS_JAR_PATH) 12 | 13 | install:: $(LIBYS_DEPS) 14 | mkdir -p $(PREFIX)/include/ 15 | install -m 644 $(LIBYS_HEADERS) $(PREFIX)/include/ 16 | mkdir -p $(PREFIX)/lib/ 17 | install -m 644 $< $(PREFIX)/lib/ 18 | ln -fs $(notdir $<) $(PREFIX)/lib/$(notdir $(LIBYS_SO_BASE)) 19 | ln -fs $(notdir $<) $(PREFIX)/lib/$(notdir $(LIBYS_SO_APIP)) 20 | ln -fs $(notdir $<) $(PREFIX)/lib/$(notdir $(LIBYS_SO_VERS)) 21 | 22 | realclean:: 23 | $(RM) -r lib/ 24 | $(RM) src/libyamlscript/Core.class 25 | 26 | test:: $(LIBYS_SO_FQNP) 27 | ls -lh lib 28 | 29 | repl-deps:: $(LIBYS_JAR_PATH) 30 | 31 | $(LIBYS_SO_FQNP): $(LIBYS_JAR_PATH) 32 | ifneq (true,$(LIBZ)) 33 | $(error *** The 'libz.$(SO)' library is required by native-image but not installed) 34 | endif 35 | mkdir -p $(dir $@) 36 | # The next command may take a long time (a minute or so) 37 | $(TIME) \ 38 | native-image \ 39 | $(NATIVE_OPTS) \ 40 | \ 41 | --shared \ 42 | -jar $< \ 43 | -o $(LIBYS_SO_NAME) 44 | mv $(LIBYS_SO_BASE) $@ 45 | mv $(LIBYS_SO_NAME).h $(LIBYS_SO_NAME).$(YAMLSCRIPT_VERSION).h 46 | ln -fs $(notdir $@) $(LIBYS_SO_APIP) 47 | ln -fs $(notdir $@) $(LIBYS_SO_VERS) 48 | ln -fs $(notdir $@) $(LIBYS_SO_BASE) 49 | touch $@ 50 | 51 | $(LIBYS_JAR_PATH): $(CORE_INSTALLED) 52 | $(LEIN) uberjar 53 | touch $@ 54 | 55 | $(CORE_INSTALLED): 56 | $(MAKE) -C $(CORE_DIR) $@ 57 | -------------------------------------------------------------------------------- /libyamlscript/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources" "target/classes"], 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.12.0"}, 4 | org.babashka/sci {:mvn/version "0.8.41"}, 5 | org.clojure/data.json {:mvn/version "2.4.0"}, 6 | yamlscript/core {:mvn/version "0.1.96"}}, 7 | :aliases 8 | {:lein2deps 9 | {:deps 10 | {io.github.borkdude/lein2deps 11 | {:git/sha "1bcf2fbbcbef611381e5e9ccdc77bec1e62ea5e5"}}, 12 | :ns-default lein2deps.build, 13 | :lein2deps/compile-java 14 | {:src-dirs ["src"], :class-dir "target/classes"}}}, 15 | :deps/prep-lib 16 | {:ensure "target/classes", :alias :lein2deps, :fn compile-java}, 17 | :mvn/repos {"public-github" {:url "git://github.com"}}} 18 | -------------------------------------------------------------------------------- /libyamlscript/project.clj: -------------------------------------------------------------------------------- 1 | ;; This code is licensed under MIT license (See License for details) 2 | ;; Copyright 2023-2025 Ingy dot Net 3 | 4 | (defproject yamlscript/libyamlscript "0.1.96" 5 | :description "Shared Library for YS" 6 | 7 | :url "https://yamlscript.org" 8 | 9 | :license 10 | {:name "MIT" 11 | :url "https://opensource.org/license/mit/"} 12 | 13 | :scm 14 | {:name "git" 15 | :url "https://github.com/yaml/yamlscript" 16 | :tag "clojure" 17 | :dir ".."} 18 | 19 | :dependencies 20 | [[org.clojure/clojure "1.12.0"] 21 | [org.babashka/sci "0.8.41"] 22 | [org.clojure/data.json "2.4.0"] 23 | [yamlscript/core "0.1.96"]] 24 | 25 | :plugins 26 | [[lein-exec "0.3.7"] 27 | [io.github.borkdude/lein-lein2deps "0.1.0"]] 28 | 29 | :prep-tasks [["compile"] ["javac"]] 30 | 31 | :java-source-paths ["src"] 32 | 33 | :profiles 34 | {:uberjar 35 | {:aot [libyamlscript.core] 36 | :main libyamlscript.core 37 | :global-vars 38 | {*assert* false 39 | *warn-on-reflection* true} 40 | :jvm-opts 41 | ["-Dclojure.compiler.direct-linking=true" 42 | "-Dclojure.spec.skip-macros=true"]}} 43 | 44 | :repositories [["public-github" {:url "git://github.com"}]] 45 | 46 | :repl-options {:init-ns libyamlscript.core} 47 | 48 | :global-vars {*warn-on-reflection* true}) 49 | -------------------------------------------------------------------------------- /libyamlscript/reflection.json: -------------------------------------------------------------------------------- 1 | ../common/reflection.json -------------------------------------------------------------------------------- /libyamlscript/src/libyamlscript/API.java: -------------------------------------------------------------------------------- 1 | // Copyright 2023-2025 Ingy dot Net 2 | // This code is licensed under MIT license (See License for details) 3 | 4 | package libyamlscript; 5 | 6 | import org.graalvm.nativeimage.c.function.CEntryPoint; 7 | import org.graalvm.nativeimage.c.type.CCharPointer; 8 | import org.graalvm.nativeimage.c.type.CTypeConversion; 9 | import org.graalvm.nativeimage.c.type.CConst; 10 | 11 | public final class API { 12 | @CEntryPoint(name = "load_ys_to_json") 13 | public static @CConst CCharPointer loadYsToJson( 14 | @CEntryPoint.IsolateThreadContext long isolateId, 15 | @CConst CCharPointer s 16 | ) { 17 | debug("API - called loadYsToJson"); 18 | 19 | String ys = CTypeConversion.toJavaString(s); 20 | 21 | debug("API - java input string: " + ys); 22 | 23 | String json = libyamlscript.core.loadYsToJson(ys); 24 | 25 | debug("API - java response string: " + json); 26 | 27 | try (CTypeConversion.CCharPointerHolder holder = 28 | CTypeConversion.toCString(json) 29 | ) { 30 | CCharPointer value = holder.get(); 31 | return value; 32 | } 33 | } 34 | 35 | public static void debug(String s) { 36 | if (System.getenv("YS_DEBUG") != null) { 37 | System.err.println(s); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /libyamlscript/src/libyamlscript/core.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | ;; This library compiles into the `libyamlscript.so` shared library. 5 | 6 | (ns libyamlscript.core 7 | (:require 8 | [clojure.data.json :as json] 9 | [sci.core :as sci] 10 | [yamlscript.common] 11 | [yamlscript.compiler :as compiler] 12 | [yamlscript.runtime :as runtime]) 13 | (:gen-class 14 | :methods [^:static [loadYsToJson [String] String]])) 15 | 16 | (declare json-write-str error-map debug) 17 | 18 | (defn -loadYsToJson 19 | "Convert a YS code string to Clojure, eval the Clojure code with SCI, encode 20 | the resulting value as JSON and return the JSON string." 21 | [^String ys-str] 22 | (debug "CLJ libyamlscript load - input string:" ys-str) 23 | (let [resp (sci/binding [sci/out *out*] 24 | (try 25 | (->> ys-str 26 | compiler/compile 27 | runtime/eval-string 28 | (assoc {} :data) 29 | json-write-str) 30 | 31 | (catch Exception e 32 | (-> e 33 | error-map 34 | json-write-str))))] 35 | (debug "CLJ libyamlscript load - response string:" resp) 36 | resp)) 37 | 38 | (defn json-write-str [data] 39 | (json/write-str 40 | data 41 | {:escape-unicode false 42 | :escape-js-separators false 43 | :escape-slash false})) 44 | 45 | (defn error-map [e] 46 | (let [err (Throwable->map e)] 47 | {:error {:cause (:cause err) 48 | :type (get-in err [:via 0 :type]) 49 | :trace (get-in err [:trace])}})) 50 | 51 | (defn debug [& msg] 52 | (when (System/getenv "YS_DEBUG") 53 | (binding [*out* *err*] 54 | (apply println msg)))) 55 | 56 | (comment 57 | ) 58 | -------------------------------------------------------------------------------- /lua/.gitignore: -------------------------------------------------------------------------------- 1 | /luarocks 2 | /lua 3 | /lua_modules 4 | /.luarocks 5 | -------------------------------------------------------------------------------- /lua/yamlscript-0.0.16.rockspec: -------------------------------------------------------------------------------- 1 | package = "yamlscript" 2 | version = "0.0.16" 3 | source = { 4 | url = "https://github.com/yaml/yamlscript/tree/main/lua/" 5 | } 6 | description = { 7 | homepage = "https://github.com/yaml/yamlscript/", 8 | license = "MIT" 9 | } 10 | build = { 11 | type = "builtin", 12 | modules = {} 13 | } 14 | -------------------------------------------------------------------------------- /nim/src/yamlscript.nim: -------------------------------------------------------------------------------- 1 | # This is just an example to get you started. A typical hybrid package 2 | # uses this file as the main entry point of the application. 3 | 4 | import yamlscriptpkg/submodule 5 | 6 | when isMainModule: 7 | echo(getWelcomeMessage()) 8 | -------------------------------------------------------------------------------- /nim/src/yamlscriptpkg/submodule.nim: -------------------------------------------------------------------------------- 1 | # This is just an example to get you started. Users of your hybrid library will 2 | # import this file by writing ``import yamlscriptpkg/submodule``. Feel free to rename or 3 | # remove this file altogether. You may create additional modules alongside 4 | # this file as required. 5 | 6 | proc getWelcomeMessage*(): string = "Hello, World!" 7 | -------------------------------------------------------------------------------- /nim/tests/config.nims: -------------------------------------------------------------------------------- 1 | switch("path", "$projectDir/../src") -------------------------------------------------------------------------------- /nim/tests/test1.nim: -------------------------------------------------------------------------------- 1 | # This is just an example to get you started. You may wish to put all of your 2 | # tests into a single file, or separate them into multiple `test1`, `test2` 3 | # etc. files (better names are recommended, just make sure the name starts with 4 | # the letter 't'). 5 | # 6 | # To run these tests, simply execute `nimble test`. 7 | 8 | import unittest 9 | 10 | import yamlscriptpkg/submodule 11 | test "correct welcome": 12 | check getWelcomeMessage() == "Hello, World!" 13 | -------------------------------------------------------------------------------- /nim/yamlscript.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.0.16" 4 | author = "Ingy döt Net" 5 | description = "Program in YAML — Code is Data" 6 | license = "MIT" 7 | srcDir = "src" 8 | installExt = @["nim"] 9 | bin = @["yamlscript"] 10 | 11 | 12 | # Dependencies 13 | 14 | requires "nim >= 1.6.6" 15 | -------------------------------------------------------------------------------- /nodejs/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /nvm/ 3 | /package-lock.json 4 | /strace.txt 5 | -------------------------------------------------------------------------------- /nodejs/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | 4 | NODE_ROOT := $(ROOT)/nodejs 5 | 6 | export NODE_PATH := $(NODE_ROOT)/lib 7 | 8 | export NODE_VERSION := v16.20.2 9 | 10 | export NVM_DIR := $(NODE_ROOT)/nvm 11 | NVM_PATH := $(NVM_DIR)/versions/node/$(NODE_VERSION) 12 | export NVM_BIN := $(NVM_PATH)/bin 13 | export NVM_INC := $(NVM_PATH)/include/node 14 | 15 | NVM_INSTALLER_URL := https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh 16 | 17 | export PATH := $(NVM_BIN):$(PATH) 18 | 19 | ifdef strace 20 | strace := strace -o strace.txt 21 | endif 22 | 23 | 24 | #------------------------------------------------------------------------------ 25 | 26 | build:: build-doc 27 | 28 | build-doc:: ReadMe.md 29 | 30 | test:: update $(LIBYS_SO_FQNP) 31 | @printf '%.0s-' {1..80}; echo 32 | $(strace) node test/test.js 33 | 34 | update: $(NVM_DIR) 35 | npm install 36 | 37 | release: $(NVM_DIR) 38 | npm publish 39 | 40 | clean:: 41 | $(RM) package-lock.json strace.txt 42 | 43 | distclean:: 44 | $(RM) -r node_modules $(NVM_DIR) 45 | 46 | $(NVM_DIR): 47 | $(call need-curl) 48 | mkdir -p $@ 49 | $(CURL) -o- $(NVM_INSTALLER_URL) | PROFILE=/dev/null bash 50 | -------------------------------------------------------------------------------- /nodejs/doc/authors.md: -------------------------------------------------------------------------------- 1 | * [Ingy döt Net](https://github.com/ingydotnet) 2 | -------------------------------------------------------------------------------- /nodejs/doc/readme.md: -------------------------------------------------------------------------------- 1 | ## NodeJS Usage 2 | 3 | A YAMLScript file `some.ys`: 4 | 5 | ```yaml 6 | !YS-v0: 7 | 8 | name =: "World" 9 | data =: load("some.yaml") 10 | fruit =: data.food.fruit 11 | 12 | num: 123 13 | greet:: "$(data.hello.rand-nth()), $name!" 14 | eat:: fruit.shuffle().first() 15 | drink:: (["Bar"] * 3).join(', ' _).str('!!!') 16 | ``` 17 | 18 | A YAML file `some.yaml`: 19 | 20 | ```yaml 21 | food: 22 | fruit: 23 | - apple 24 | - banana 25 | - cherry 26 | - date 27 | 28 | hello: 29 | - Aloha 30 | - Bonjour 31 | - Ciao 32 | - Dzień dobry 33 | ``` 34 | 35 | NodeJS file `ys-load.js`: 36 | 37 | ```js 38 | let fs = require("fs"); 39 | let YS = require("@yaml/yamlscript"); 40 | 41 | let input = fs.readFileSync("some.ys", "utf8"); 42 | 43 | let ys = new YS(); 44 | 45 | let data = ys.load(input); 46 | 47 | console.log(data); 48 | ``` 49 | 50 | Run: 51 | 52 | ```text 53 | $ node ys-load.js | jq 54 | { 55 | num: 123, 56 | greet: 'Bonjour, World!', 57 | eat: 'cherry', 58 | drink: 'Bar, Bar, Bar!!!' 59 | } 60 | ``` 61 | 62 | 63 | ## Installation 64 | 65 | You can install this module like any other NodeJS module: 66 | 67 | ```bash 68 | $ npm install @yaml/yamlscript 69 | ``` 70 | 71 | but you will need to have a system install of `libyamlscript.so`. 72 | 73 | One simple way to do that is with: 74 | 75 | ```bash 76 | $ curl https://yamlscript.org/install | bash 77 | ``` 78 | 79 | > Note: The above command will install the latest version of the YAMLScript 80 | command line utility, `ys`, and the shared library, `libyamlscript.so`, into 81 | `~/.local/bin` and `~/.local/lib` respectively. 82 | 83 | See for more info. 84 | -------------------------------------------------------------------------------- /nodejs/lib/@yaml: -------------------------------------------------------------------------------- 1 | . -------------------------------------------------------------------------------- /nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yaml/yamlscript", 3 | "version": "0.1.96", 4 | "description": "Program in YAML — Code is Data", 5 | "main": "lib/yamlscript/index.js", 6 | "author": "Ingy döt Net", 7 | "license": "MIT", 8 | "dependencies": { 9 | "ffi-napi": "4.0.3", 10 | "ref-napi": "3.0.3" 11 | }, 12 | "directories": { 13 | "test": "test" 14 | }, 15 | "scripts": { 16 | "test": "make test" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/yaml/yamlscript.git" 21 | }, 22 | "bugs": { 23 | "url": "https://github.com/yaml/yamlscript/issues" 24 | }, 25 | "homepage": "https://github.com/yaml/yamlscript#readme" 26 | } 27 | -------------------------------------------------------------------------------- /nodejs/test/test.js: -------------------------------------------------------------------------------- 1 | let YS = require("@yaml/yamlscript"); 2 | 3 | let ys = new YS(); 4 | 5 | let data1 = ys.load("foo: 6 * 7"); 6 | 7 | console.log(data1); 8 | 9 | let data2 = ys.load("!YS-v0:\nfoo:: 6 * 7"); 10 | 11 | console.log(data2); 12 | -------------------------------------------------------------------------------- /perl-alien/.gitignore: -------------------------------------------------------------------------------- 1 | /cpan/ 2 | /Alien-YAMLScript-* 3 | -------------------------------------------------------------------------------- /perl-alien/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/zild.mk 3 | 4 | #------------------------------------------------------------------------------ 5 | clean:: 6 | $(RM) -r cpan Alien-YAMLScript* 7 | 8 | build-doc:: 9 | -------------------------------------------------------------------------------- /perl-alien/Meta: -------------------------------------------------------------------------------- 1 | =meta: 0.0.2 2 | 3 | base: ../Meta 4 | 5 | name: Alien-YAMLScript 6 | version: 0.1.96 7 | 8 | language: perl 9 | 10 | author: 11 | cpan: INGY 12 | 13 | requires: 14 | perl: 5.16.0 15 | Cpanel::JSON::XS: 4.37 16 | 17 | test: 18 | requires: 19 | Test2::V0: 0.000159 20 | Test::Alien: 2.80 21 | 22 | =zild: 23 | no-about: true 24 | no_changes_yaml: true 25 | no-check: true 26 | no-git-update: true 27 | no-readme: true 28 | no-travis: true 29 | test-000: none 30 | 31 | dzil: 32 | postamble: | 33 | [AlienBuild] 34 | [Prereqs / ConfigureRequires] 35 | Alien::Build::Plugin::Download::GitHub = 0.10 36 | -------------------------------------------------------------------------------- /perl-alien/alienfile: -------------------------------------------------------------------------------- 1 | use alienfile; 2 | 3 | my $libyamlscript_version = '0.1.96'; 4 | 5 | # Always use a share install 6 | # We cannot use a system install, because we need to know exactly 7 | # which version we are installing. 8 | probe sub { 'share' }; 9 | 10 | share { 11 | my $os = $^O; 12 | $os = 'macos' unless $os eq 'linux'; 13 | 14 | my $arch = meta->prop->{platform}{cpu}{arch}{name}; 15 | $arch = 'x64' unless $arch eq 'aarch64'; 16 | 17 | plugin 'Download::GitHub' => ( 18 | github_user => 'yaml', 19 | github_repo => 'yamlscript', 20 | asset => 1, 21 | asset_name => qr/^libyamlscript-\Q$libyamlscript_version\E-$os-$arch/, 22 | asset_format => 'tar.xz', 23 | ); 24 | 25 | build [ 26 | '%{make} install PREFIX=%{.install.prefix}', 27 | ]; 28 | }; 29 | -------------------------------------------------------------------------------- /perl-alien/doc/Alien/YAMLScript.md: -------------------------------------------------------------------------------- 1 | Alien::YAMLScript 2 | ================= 3 | 4 | Find or install libyamlscript 5 | 6 | 7 | ## Synopsis 8 | 9 | 10 | ``` 11 | use Alien::YAMLScript; 12 | 13 | my $alien = Alien::YAMLScript->new; 14 | say $alien->libs; 15 | say $alien->cflags; 16 | ``` 17 | 18 | 19 | ## Status 20 | 21 | This is ALPHA software. 22 | Expect things to change. 23 | 24 | 25 | ## Description 26 | 27 | This [Alien](https://metacpan.org/pod/Alien) module provides access to the 28 | libyamlscript shared library. You are unlikely to need to use this module 29 | directly. 30 | See [YAMLScript](https://metacpan.org/pod/YAMLScript) for a more likely 31 | entrypoint. 32 | 33 | 34 | ## See Also 35 | 36 | * [YAMLScript Site](https://yamlscript.org) 37 | * [YAML](https://yaml.org) 38 | * [Clojure](https://clojure.org) 39 | 40 | 41 | ## Authors 42 | 43 | * [Ingy döt Net](https://github.com/ingydotnet) 44 | * [José Joaquín Atria](https://github.com/jjatria) 45 | 46 | 47 | ## Copyright and License 48 | 49 | Copyright 2022-2025 by Ingy döt Net 50 | 51 | This is free software, licensed under: 52 | 53 | The MIT (X11) License 54 | -------------------------------------------------------------------------------- /perl-alien/lib/Alien/YAMLScript.pm: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | 4 | package Alien::YAMLScript; 5 | 6 | our $VERSION = '0.1.96'; 7 | 8 | use parent 'Alien::Base'; 9 | 10 | our $libyamlscript_version = $VERSION; 11 | 12 | die "Alien::YAMLScript $VERSION requires libyamlscript $libyamlscript_version" . 13 | "but you have " . __PACKAGE__->version 14 | unless Alien::YAMLScript->exact_version($libyamlscript_version); 15 | 16 | 1; 17 | -------------------------------------------------------------------------------- /perl-alien/pkg/make-cpan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | set -x 4 | 5 | cp alienfile cpan 6 | -------------------------------------------------------------------------------- /perl-alien/pkg/no-test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaml/yamlscript/b47d953d40bb3dec8065e1fed45eb531b1acad0a/perl-alien/pkg/no-test -------------------------------------------------------------------------------- /perl-alien/test/ffi.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use Test2::V0 -target => 'Alien::YAMLScript'; 4 | use Test::Alien; 5 | use Cpanel::JSON::XS; 6 | 7 | alien_ok $CLASS; 8 | 9 | ffi_ok { symbols => [ 'graal_create_isolate', 'load_ys_to_json' ] }, 10 | with_subtest { 11 | my ($ffi) = @_; 12 | 13 | 14 | my $graal = $ffi->function( graal_create_isolate => [qw( opaque opaque* opaque* )] => 'int' ) 15 | ->( undef, \my $isolate, \my $thread); 16 | 17 | is $graal, 0, 'Can create GraalVM isolate'; 18 | 19 | my $load = $ffi->function( 20 | load_ys_to_json => [qw( sint64 string )] => 'string' => sub { 21 | my ( $xsub, $ys ) = @_; 22 | decode_json $xsub->( $thread, $ys ); 23 | }, 24 | ); 25 | 26 | is $load->(<<'...'), 27 | !YS-v0: 28 | foo:: 1 .. 10 29 | ... 30 | { data => { foo => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] } }, 31 | 'Can load YS to JSON'; 32 | }; 33 | 34 | done_testing; 35 | -------------------------------------------------------------------------------- /perl/.gitignore: -------------------------------------------------------------------------------- 1 | /ToDo 2 | /cpan/ 3 | /local/ 4 | /YAMLScript-* 5 | -------------------------------------------------------------------------------- /perl/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | include $(COMMON)/zild.mk 4 | 5 | test ?= test/ 6 | 7 | export PATH := $(ROOT)/perl/bin:$(PATH) 8 | 9 | PERL_VERSION := $(shell grep '^version:' Meta | cut -d' ' -f2) 10 | ALIEN_DIST_DIR := $(ROOT)/perl-alien/Alien-YAMLScript-$(PERL_VERSION) 11 | ALIEN_BLIB_LIB := $(ALIEN_DIST_DIR)/blib/lib 12 | 13 | ifneq (,$(shell command -v cpanm)) 14 | PERLOK := true 15 | endif 16 | 17 | CPAN_DEPS := \ 18 | Test2::V0 \ 19 | FFI::CheckLib \ 20 | FFI::Platypus \ 21 | Cpanel::JSON::XS \ 22 | 23 | LOCAL_LIB := local 24 | 25 | export PERL5LIB := $(LOCAL_LIB)/lib/perl5 26 | 27 | #------------------------------------------------------------------------------ 28 | 29 | ifdef PERLOK 30 | test:: $(LOCAL_LIB) 31 | prove -l $${TEST_VERBOSE:+'-v'} $(test) 32 | 33 | test-alien: $(ALIEN_BLIB_LIB) 34 | LD_LIBRARY_PATH= \ 35 | DYLD_LIBRARY_PATH= \ 36 | prove -I$< -l $${TEST_VERBOSE:+'-v'} $(test) 37 | endif 38 | 39 | clean:: 40 | $(RM) -r cpan YAMLScript-* 41 | 42 | realclean:: 43 | $(RM) -r $(LOCAL_LIB) 44 | 45 | $(ALIEN_BLIB_LIB): $(ALIEN_DIST_DIR) 46 | ( \ 47 | cd $< && \ 48 | perl Makefile.PL && \ 49 | make \ 50 | ) 51 | touch $@ 52 | 53 | $(ALIEN_DIST_DIR): 54 | $(MAKE) -C $(ROOT)/perl-alien distdir 55 | 56 | $(LOCAL_LIB): 57 | cpanm -L $@ -n $(CPAN_DEPS) 58 | -------------------------------------------------------------------------------- /perl/Meta: -------------------------------------------------------------------------------- 1 | =meta: 0.0.2 2 | 3 | base: ../Meta 4 | 5 | name: YAMLScript 6 | version: 0.1.96 7 | 8 | language: perl 9 | 10 | author: 11 | cpan: INGY 12 | 13 | requires: 14 | perl: 5.16.0 15 | Alien::YAMLScript: 0.1.96 16 | FFI::CheckLib: 0.31 17 | FFI::Platypus: 2.08 18 | Cpanel::JSON::XS: 4.37 19 | 20 | test: 21 | requires: 22 | Test2::V0: 0.000159 23 | 24 | =zild: 25 | no-about: true 26 | no_changes_yaml: true 27 | no-check: true 28 | no-git-update: true 29 | no-readme: true 30 | no-travis: true 31 | test-000: none 32 | -------------------------------------------------------------------------------- /perl/lib/YAMLScript/Alien.pm: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | 4 | package YAMLScript::Alien; 5 | 6 | use Alien::YAMLScript; 7 | 8 | # Alien::YAMLScript finds the proper libyamlscript version, but we need to be 9 | # using the proper version of Alien::YAMLScript: 10 | die "\$YAMLScript::VERSION ($YAMLScript::VERSION) and " . 11 | "\$Alien::YAMLScript::VERSION($Alien::YAMLScript::VERSION) " . 12 | "must be the same version" 13 | unless $YAMLScript::VERSION eq $Alien::YAMLScript::VERSION; 14 | -------------------------------------------------------------------------------- /perl/test/load.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use Test2::V0 -target => 'YAMLScript'; 4 | 5 | my $program = <<'...'; 6 | !YS-v0: 7 | foo:: 1 .. 10 8 | ... 9 | 10 | is CLASS->new->load($program), 11 | { foo => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] }, 12 | 'Returns data'; 13 | 14 | # like dies { CLASS->new->load("mapping\nerror::") }, 15 | # qr/libyamlscript: mapping values are not allowed/, 16 | # 'Dies with libyamlscript error'; 17 | 18 | done_testing; 19 | -------------------------------------------------------------------------------- /php/Changelog.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | 0.0.16 5 | ------ 6 | 7 | * Initial release 8 | -------------------------------------------------------------------------------- /php/License: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022-2025 Ingy dot Net 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /php/ReadMe.md: -------------------------------------------------------------------------------- 1 | YAMLScript 2 | ========== 3 | 4 | Program in YAML — Code is Data 5 | 6 | 7 | ## Authors 8 | 9 | * [Ingy döt Net](https://github.com/ingydotnet) 10 | 11 | 12 | ## Copyright and License 13 | 14 | Copyright 2022-2025 by Ingy döt Net 15 | 16 | This is free software, licensed under: 17 | 18 | The MIT (X11) License 19 | -------------------------------------------------------------------------------- /php/YAMLScript.php: -------------------------------------------------------------------------------- 1 | Note: The above command will install the latest version of the YAMLScript 56 | command line utility, `ys`, and the shared library, `libyamlscript.so`, into 57 | `~/local/bin` and `~/.local/lib` respectively. 58 | 59 | See for more info. 60 | -------------------------------------------------------------------------------- /python/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description_file = ReadMe.md 3 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | version = '0.1.96' 2 | 3 | from setuptools import setup 4 | import pathlib 5 | 6 | root = pathlib.Path(__file__).parent.resolve() 7 | 8 | long_description = \ 9 | (root / '.long_description.md') \ 10 | .read_text(encoding='utf-8') 11 | 12 | setup( 13 | name = 'yamlscript', 14 | version = version, 15 | description = 'Program in YAML — Code is Data', 16 | license = 'MIT', 17 | url = 'https://github.com/ingydotnet/yamlscript', 18 | 19 | author = 'Ingy döt Net', 20 | author_email = 'ingy@ingy.net', 21 | 22 | packages = ['yamlscript'], 23 | package_dir = {'': 'lib'}, 24 | 25 | python_requires = '>=3.6, <4', 26 | install_requires = [ 27 | 'pyyaml', 28 | ], 29 | setup_requires = [ 30 | 'wheel', 31 | ], 32 | 33 | keywords = ['yaml', 'language'], 34 | classifiers = [ 35 | 'Development Status :: 3 - Alpha', 36 | 'Intended Audience :: Developers', 37 | 'License :: OSI Approved :: MIT License', 38 | 'Programming Language :: Python :: 3', 39 | 'Programming Language :: Python :: 3.6', 40 | 'Programming Language :: Python :: 3.7', 41 | 'Programming Language :: Python :: 3.8', 42 | 'Programming Language :: Python :: 3.9', 43 | 'Programming Language :: Python :: 3 :: Only', 44 | ], 45 | 46 | long_description = long_description, 47 | long_description_content_type = 'text/markdown', 48 | ) 49 | -------------------------------------------------------------------------------- /python/test/test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | def modules_compile(): 4 | # import yamlscript 5 | return "ok" 6 | 7 | def test_modules_compile(): 8 | assert modules_compile() == "ok" 9 | -------------------------------------------------------------------------------- /raku/.gitignore: -------------------------------------------------------------------------------- 1 | /sdist/ 2 | /target/ 3 | .precomp 4 | -------------------------------------------------------------------------------- /raku/META6.json: -------------------------------------------------------------------------------- 1 | { "api": 0 2 | , "name": "YAMLScript" 3 | , "version": "0.1.96" 4 | , "description": "Program in YAML — Code is Data" 5 | , "auth": "zef:ingy" 6 | , "provides": 7 | { "YAMLScript": "lib/YAMLScript.rakumod" 8 | } 9 | , "depends": [] 10 | , "build-depends": [] 11 | , "test-depends": [] 12 | , "tags": 13 | [ "yaml" 14 | , "language" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /raku/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | 4 | test ?= t/* 5 | 6 | export RAKULIB=$(ROOT)/raku/lib 7 | 8 | RAKU := $(shell command -v raku) 9 | 10 | #------------------------------------------------------------------------------ 11 | test:: 12 | ifdef RAKU 13 | prove $${TEST_VERBOSE:+'-v'} $(test) 14 | endif 15 | 16 | release: 17 | fez upload 18 | 19 | dist:: 20 | fez upload --dry-run 21 | 22 | clean:: 23 | $(RM) -r .precomp/ lib/.precomp/ sdist/ 24 | -------------------------------------------------------------------------------- /raku/t/00-use.rakutest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env raku 2 | 3 | use Test; 4 | sub from-j($t) { ::("Rakudo::Internals::JSON").from-json($t); } 5 | 6 | 7 | my @xs = 'lib'.IO; 8 | my %fs; 9 | while @xs { 10 | for @xs.pop.dir -> $f { 11 | %fs{$f} = 1 if $f.extension eq 'rakumod'; 12 | @xs.push($f) if $f.d; 13 | } 14 | } 15 | 16 | plan 1 +%fs.keys; 17 | 18 | my %meta = from-j('META6.json'.IO.slurp); 19 | for %meta.keys -> $dn { 20 | %fs{%meta{$dn}.IO.relative}--; 21 | use-ok $dn; 22 | } 23 | 24 | ok +%fs.grep(*.value != 0) == 0, 'provides 1:1 files in lib'; 25 | -------------------------------------------------------------------------------- /raku/t/01-load.rakutest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env raku 2 | 3 | use Test; 4 | use YAMLScript; 5 | 6 | plan 1; 7 | 8 | my %wanted = 9 | foo => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], 10 | ; 11 | 12 | my $program = q:to/.../; 13 | !YS-v0: 14 | foo:: 1 .. 10 15 | ... 16 | 17 | my YAMLScript $ys.=new; 18 | is-deeply %wanted, $ys.load($program), 'expected output for basic script'; 19 | 20 | $ys.DESTROY; 21 | -------------------------------------------------------------------------------- /ruby/.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /gem/ 7 | /pkg/ 8 | /.rake_tasks* 9 | /spec/reports/ 10 | /tmp/ 11 | /Gemfile.lock 12 | -------------------------------------------------------------------------------- /ruby/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # Specify your gem's dependencies in yamlscript.gemspec 6 | gemspec 7 | 8 | gem "rake", "~> 13.0" 9 | gem "minitest", "~> 5.20.0" 10 | -------------------------------------------------------------------------------- /ruby/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | 4 | RUBY := $(shell command -v bundle) 5 | 6 | RAKE_CMDS := \ 7 | build \ 8 | release \ 9 | test \ 10 | 11 | export GEM_HOME=gem 12 | 13 | 14 | #------------------------------------------------------------------------------ 15 | 16 | build:: build-doc 17 | 18 | build-doc:: ReadMe.md 19 | 20 | ifdef RUBY 21 | update: 22 | bundle install 23 | 24 | $(RAKE_CMDS):: $(GEM_HOME) 25 | bundle exec rake $@ 26 | 27 | $(GEM_HOME): 28 | gem install minitest -v 5.20.0 29 | bundle install 30 | endif 31 | 32 | clean:: 33 | $(RM) Gemfile.lock .rake_tasks* 34 | $(RM) -r pkg 35 | 36 | realclean:: 37 | $(RM) -r $(GEM_HOME) 38 | -------------------------------------------------------------------------------- /ruby/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/gem_tasks" 4 | require "minitest/test_task" 5 | 6 | Rake::Task["release:guard_clean"].clear 7 | 8 | # Disable tagging for `rake release` 9 | namespace :release do 10 | task :commit do 11 | puts "Overriding commit task" 12 | end 13 | task :guard_clean do 14 | puts "Overriding guard_clean task" 15 | end 16 | task :tag do 17 | puts "Overriding tag task" 18 | end 19 | task :push do 20 | puts "Overriding push task" 21 | end 22 | end 23 | 24 | Minitest::TestTask.create(:test) do |t| 25 | t.libs << "test" 26 | t.libs << "lib" 27 | t.warning = false 28 | t.test_globs = ["test/**/*_test.rb"] 29 | end 30 | 31 | task :default => :test 32 | -------------------------------------------------------------------------------- /ruby/doc/authors.md: -------------------------------------------------------------------------------- 1 | * [Ingy döt Net](https://github.com/ingydotnet) 2 | * [Delon R.Newman](https://github.com/delonnewman) 3 | -------------------------------------------------------------------------------- /ruby/doc/readme.md: -------------------------------------------------------------------------------- 1 | ## Ruby Usage 2 | 3 | File `prog.rb`: 4 | 5 | ```ruby 6 | require 'yamlscript' 7 | input = IO.read('file.ys') 8 | ys = YAMLScript.new 9 | data = ys.load(input) 10 | puts data 11 | ``` 12 | 13 | File `file.ys`: 14 | 15 | ```yaml 16 | !YS-v0: 17 | 18 | name =: "World" 19 | 20 | foo: [1, 2, ! inc(41)] 21 | bar:: load("other.yaml") 22 | baz:: "Hello, $name!" 23 | ``` 24 | 25 | File `other.yaml`: 26 | 27 | ```yaml 28 | oh: Hello 29 | ``` 30 | 31 | Run: 32 | 33 | ```text 34 | $ ruby prog.rb 35 | {"foo"=>[1, 2, 42], "bar"=>{"oh"=>"Hello"}, "baz"=>"Hello, World!"} 36 | ``` 37 | 38 | 39 | ## Installation 40 | 41 | You can install this module like any other Ruby module: 42 | 43 | ```bash 44 | gem install yamlscript 45 | ``` 46 | 47 | but you will need to have a system install of `libyamlscript.so`. 48 | 49 | One simple way to do that is with: 50 | 51 | ```bash 52 | curl https://yamlscript.org/install | bash 53 | ``` 54 | 55 | > Note: The above command will install the latest version of the YAMLScript 56 | command line utility, `ys`, and the shared library, `libyamlscript.so`, into 57 | `~/local/bin` and `~/.local/lib` respectively. 58 | 59 | See for more info. 60 | -------------------------------------------------------------------------------- /ruby/lib/yamlscript/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class YAMLScript 4 | VERSION = "0.1.96" 5 | end 6 | -------------------------------------------------------------------------------- /ruby/test/lib/yamlscript_test.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | require_relative '../../lib/yamlscript' 4 | 5 | class YAMLScriptTest < Minitest::Test 6 | def setup 7 | @ys = YAMLScript.new 8 | end 9 | 10 | def test_load_yaml_data 11 | data = @ys.load('a: 1') 12 | 13 | assert_equal data['a'], 1 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ruby/yamlscript.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "lib/yamlscript/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = "yamlscript" 7 | spec.version = YAMLScript::VERSION 8 | spec.authors = ["Ingy döt Net", "Delon Newman"] 9 | spec.email = ["ingy@ingy.net", "contact@delonnewman.name"] 10 | 11 | spec.summary = "Program in YAML — Code is Data" 12 | spec.description = "Program in YAML — Code is Data" 13 | spec.homepage = "https://github.com/yaml/yamlscript" 14 | spec.required_ruby_version = ">= 2.4.0" 15 | 16 | spec.metadata["homepage_uri"] = spec.homepage 17 | spec.metadata["source_code_uri"] = spec.homepage 18 | spec.metadata["changelog_uri"] = \ 19 | "https://github.com/yaml/yamlscript/tree/main/ruby/ChangeLog.md" 20 | 21 | spec.files = Dir.chdir(File.expand_path(__dir__)) do 22 | `git ls-files -z`.split("\x0").reject { 23 | |f| f.match(%r{\A(?:test|spec|features)/}) 24 | } 25 | end 26 | spec.bindir = "exe" 27 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } 28 | spec.require_paths = ["lib"] 29 | 30 | spec.add_dependency "minitest", "~> 5.20.0" 31 | end 32 | -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | /Cargo.lock 2 | /target/ 3 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yamlscript" 3 | version = "0.1.96" 4 | edition = "2021" 5 | description = "Program in YAML — Code is Data" 6 | license = "MIT" 7 | readme = "ReadMe.md" 8 | repository = "https://github.com/yaml/yamlscript" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | dlopen = "0.1.8" 14 | libc = "0.2.150" 15 | serde = { version = "1.0.193", features = ["derive"] } 16 | serde_json = "1.0.109" 17 | -------------------------------------------------------------------------------- /rust/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/binding.mk 3 | 4 | CARGO := $(shell command -v cargo) 5 | 6 | CARGO_CMDS := \ 7 | build \ 8 | clean \ 9 | install \ 10 | publish \ 11 | test \ 12 | 13 | 14 | #------------------------------------------------------------------------------ 15 | build:: build-doc 16 | 17 | build-doc:: ReadMe.md 18 | 19 | ifdef CARGO 20 | $(CARGO_CMDS):: 21 | cargo $@ 22 | 23 | release: publish 24 | endif 25 | -------------------------------------------------------------------------------- /rust/doc/authors.md: -------------------------------------------------------------------------------- 1 | * [Ingy döt Net](https://github.com/ingydotnet) 2 | * [Ethiraric](https://github.com/Ethiraric) 3 | -------------------------------------------------------------------------------- /rust/doc/readme.md: -------------------------------------------------------------------------------- 1 | ## Rust Usage 2 | 3 | Create a new Rust project: 4 | 5 | ```text 6 | $ cargo new --bin prog 7 | $ cd prog 8 | ``` 9 | 10 | Add the file `src/main.rs`: 11 | 12 | ```rust 13 | use std::fs::File; 14 | use std::io::prelude::*; 15 | use yamlscript::YAMLScript; 16 | 17 | fn main() -> std::io::Result<()> { 18 | let mut file = File::open("file.ys")?; 19 | let mut input = String::new(); 20 | file.read_to_string(&mut input)?; 21 | let ys = YAMLScript::new().unwrap(); 22 | let data = ys.load::(&input).unwrap(); 23 | println!("{data:?}"); 24 | Ok(()) 25 | } 26 | ``` 27 | 28 | Add file `file.ys`: 29 | 30 | ```yaml 31 | !YS-v0: 32 | 33 | name =: "World" 34 | 35 | foo: [1, 2, ! inc(41)] 36 | bar:: load("other.yaml") 37 | baz:: "Hello, $name!" 38 | ``` 39 | 40 | Add file `other.yaml`: 41 | 42 | ```yaml 43 | oh: Hello 44 | ``` 45 | 46 | Run: 47 | 48 | ```text 49 | $ curl https://yamlscript.org/install | bash 50 | $ cargo add yamlscript 51 | $ cargo add serde_json 52 | $ cargo run 53 | Finished dev [unoptimized + debuginfo] target(s) in 0.02s 54 | Running `target/debug/prog` 55 | Object {"bar": Object {"oh": String("Hello")}, "baz": String("Hello, World!"), "foo": Array [Number(1), Number(2), Number(42)]} 56 | ``` 57 | 58 | 59 | ## Installation 60 | 61 | You can install this module like any other Rust module: 62 | 63 | ```bash 64 | cargo add yamlscript 65 | ``` 66 | 67 | but you will need to have a system install of `libyamlscript.so`. 68 | 69 | One simple way to do that is with: 70 | 71 | ```bash 72 | curl https://yamlscript.org/install | bash 73 | ``` 74 | 75 | > Note: The above command will install the latest version of the YAMLScript 76 | command line utility, `ys`, and the shared library, `libyamlscript.so`, into 77 | `~/.local/bin` and `~/.local/lib` respectively. 78 | 79 | See for more info. 80 | -------------------------------------------------------------------------------- /rust/examples/eval_ys_to_json.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let input = std::io::read_to_string(std::io::stdin()).unwrap(); 3 | let ys = yamlscript::YAMLScript::new().unwrap(); 4 | let output = ys.load::(&input).unwrap(); 5 | println!("{output}"); 6 | } 7 | -------------------------------------------------------------------------------- /sample/advent/a-bit-of-data.ys: -------------------------------------------------------------------------------- 1 | # a-bit-of-data.ys -- Data for a-bit-before 2 | 3 | holiday: [Christmas, Hanukkah, Kwanzaa, Winter, Solstice, Yule, Saturnalia] 4 | place: [house, apartment, condo, igloo, cave, castle, mansion, tent, hut] 5 | animal: [mouse, cat, dog, bird, fish, snake, pug, frog, turtle, rabbit] 6 | hang-by: [chimney, fireplace, window, toilet, door, wall, faucet, tree] 7 | saint: [Nicholas, Grinchy, Krampus, Valentines, Jack, Frosty, Santa, Bernard] 8 | children: [children, kids, tots, babies, offspring, spawn, progeny, brats] 9 | beds: [beds, bunks, cots, hammocks, pallets, mats, futons, blankets] 10 | adj: [sweet, sour, salty, bitter, spicy, savory, pungent, tart, tangy] 11 | candies: [candies, chocolates, sweets, cookies, cakes, pies, pastries] 12 | relative: [mamma, papa, sis, bro, aunty, uncle, cuz, gram, gramps] 13 | hat: [cap, hat, bonnet, beanie, beret, fedora, sombrero, helmet, crown] 14 | activity: [nap, sleep, slumber, snooze, rest, hibernation, siesta, doze] 15 | outside: [lawn, yard, field, forest, woods, jungle, desert, tundra, ocean] 16 | seat: [bed, chair, couch, sofa, futon, hammock, bench, stool, throne] 17 | flyer: [flash, bolt, bullet, rocket, plane, jet, eagle, hawk, falcon] 18 | covers: [shutters, blinds, curtains, shades, drapes, screens, panels] 19 | cover: [shutter, blind, curtain, shade, drape, screen, panel] 20 | luminary: [moon, sun, star, planet, comet, asteroid, meteor, satellite] 21 | fallers: [snow, rain, hail, sleet, ice, slush, frost, dew, fog, mist] 22 | outers: [trees, bushes, shrubs, flowers, grass, weeds, rocks, dirt, sand] 23 | arrive: [appear, arrive, come, materialize, manifest, show up, land] 24 | vehicle: [sleigh, car, truck, van, bus, train, plane, boat, ship, rocket] 25 | service-animals: [reindeer, horses, camels, elephants, oxen, donkeys, mules] 26 | -------------------------------------------------------------------------------- /sample/advent/fruits.yaml: -------------------------------------------------------------------------------- 1 | # fruits.yaml 2 | - apple 3 | - banana 4 | - cherry 5 | -------------------------------------------------------------------------------- /sample/advent/grocery.yaml: -------------------------------------------------------------------------------- 1 | # grocery.yaml 2 | !YS-v0: 3 | 4 | ::: 5 | - bread 6 | - fruits: ! load('fruits.yaml') 7 | - milk 8 | -------------------------------------------------------------------------------- /sample/advent/hearsay-rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hearsay-rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | yamlscript = "0.1.2" 10 | -------------------------------------------------------------------------------- /sample/advent/hearsay-rust/ReadMe.md: -------------------------------------------------------------------------------- 1 | Run: 2 | 3 | ``` 4 | $ LD_LIBRARY_PATH=/usr/local/lib cargo run 5 | "data":"I heard that @ethiraric uses YS in their Python code!"} 6 | $ 7 | ``` 8 | -------------------------------------------------------------------------------- /sample/advent/hearsay-rust/hearsay.ys: -------------------------------------------------------------------------------- 1 | ../hearsay.ys -------------------------------------------------------------------------------- /sample/advent/hearsay-rust/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let input = std::fs::read_to_string("hearsay.ys").unwrap(); 3 | let output = yamlscript::load(&input).unwrap(); 4 | println!("{output}"); 5 | } 6 | -------------------------------------------------------------------------------- /sample/advent/hearsay.pl: -------------------------------------------------------------------------------- 1 | use v5.16.0; 2 | use YAMLScript; 3 | use Slurp; 4 | my $program = slurp 'hearsay.ys'; 5 | say YAMLScript->new->load($program); 6 | -------------------------------------------------------------------------------- /sample/advent/hearsay.raku: -------------------------------------------------------------------------------- 1 | use YAMLScript; 2 | my $program = slurp 'hearsay.ys'; 3 | my YAMLScript $ys .= new; 4 | say $ys.load($program); 5 | -------------------------------------------------------------------------------- /sample/advent/hearsay.ys: -------------------------------------------------------------------------------- 1 | # ys --load hearsay.ys | jq -r . 2 | 3 | !YS-v0 4 | 5 | hackers =:: 6 | - ethiraric 7 | - ingydotnet 8 | - jjatria 9 | - tony-o 10 | 11 | languages =:: 12 | - Perl 13 | - Python 14 | - Raku 15 | - Rust 16 | 17 | =>: "I heard that @$rand-nth(hackers) uses YS 18 | in their $rand-nth(languages) code!" 19 | -------------------------------------------------------------------------------- /sample/advent/lol.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | count =: atom(0) 4 | counter =: \(swap! count inc) 5 | 6 | say: counter() 7 | say: counter() 8 | say: counter() 9 | -------------------------------------------------------------------------------- /sample/advent/madlibs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | data =: 4 | load: "madlibs-data.yaml" 5 | 6 | defn word(kind): 7 | rand-nth: 8 | data.get(name(kind)) 9 | 10 | say: | 11 | Dear $word(:name), 12 | 13 | You should go to $word(:city). 14 | I really think you would $word(:feel) it there. 15 | 16 | Sincerely, $word(:name) 17 | -------------------------------------------------------------------------------- /sample/advent/madlibs-data.yaml: -------------------------------------------------------------------------------- 1 | name: 2 | - John 3 | - Mary 4 | - Bob 5 | - Jane 6 | - Mike 7 | - Alice 8 | - Tom 9 | - Jerry 10 | - Bill 11 | - Sue 12 | - Fred 13 | - Joe 14 | 15 | verb: 16 | - go 17 | - run 18 | - walk 19 | - jump 20 | - skip 21 | - crawl 22 | - fly 23 | - swim 24 | - drive 25 | - bike 26 | - skate 27 | - dance 28 | 29 | adverb: 30 | - quickly 31 | - slowly 32 | - carefully 33 | - recklessly 34 | - quietly 35 | - loudly 36 | - stealthily 37 | - noisily 38 | - gracefully 39 | - clumsily 40 | - lazily 41 | - energetically 42 | 43 | adjective: 44 | - big 45 | - small 46 | - tall 47 | - short 48 | - fat 49 | - skinny 50 | - wide 51 | - narrow 52 | - long 53 | - short 54 | - fast 55 | - slow 56 | 57 | animal: 58 | - dog 59 | - cat 60 | - bird 61 | - fish 62 | - mouse 63 | - snake 64 | - frog 65 | - turtle 66 | - rabbit 67 | - horse 68 | - cow 69 | - pig 70 | 71 | city: 72 | - New York 73 | - London 74 | - Paris 75 | - Tokyo 76 | - Los Angeles 77 | - Chicago 78 | - Rome 79 | - Berlin 80 | - Madrid 81 | - Amsterdam 82 | - Toronto 83 | - Hell 84 | 85 | feel: 86 | - love 87 | - hate 88 | - like 89 | - dislike 90 | - enjoy 91 | - detest 92 | - adore 93 | - despise 94 | - appreciate 95 | - loathe 96 | - cherish 97 | - abhor 98 | -------------------------------------------------------------------------------- /sample/advent/silly.ys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | my-yaml =: | 4 | - Hello 5 | - Salutations 6 | - Ho Ho Ho 7 | - Merry Christmas 8 | - Happy Holidays 9 | - Seasons Greetings 10 | - Happy New Year 11 | - Happy Hanukkah 12 | - Happy Kwanzaa 13 | 14 | my-json =: | 15 | [ "World", 16 | "Santa", 17 | "Elves", 18 | "Reindeer", 19 | "Snowman", 20 | "Mrs. Claus", 21 | "Rudolph", 22 | "Frosty", 23 | "Kids" ] 24 | 25 | greets =: yaml/load(my-yaml) 26 | 27 | names =: json/load(my-json) 28 | 29 | say: "$rand-nth(greets), $rand-nth(names)!!" 30 | -------------------------------------------------------------------------------- /sample/advent/thread-last.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | ->> (1 .. 10): 4 | WWW: 'before map' 5 | map: inc 6 | WWW: 'after map' 7 | filter: \((_ % 2).!) # odd? 8 | WWW: 'after filter' 9 | reduce add: 10 | WWW: 'after reduce' 11 | say: 12 | WWW: 13 | -------------------------------------------------------------------------------- /sample/advent/tree.ys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | defn main(width=5): 4 | say: tree(width) 5 | 6 | defn tree(width): 7 | top =: (width .. 1) 8 | .map(\(line width _)) 9 | .join("\n") 10 | 11 | trunk =: trunk(width) * 2 12 | 13 | =>: |- 14 | $top 15 | $trunk 16 | 17 | defn trunk(num): "$spaces(num)*\n" 18 | 19 | defn line(width, num): 20 | :: "`stars` is a lexically defined function" 21 | stars =: \(_.++ * '*') 22 | 23 | join '': 24 | spaces: num 25 | stars: (width - num) * 2 26 | 27 | defn spaces(num): num * ' ' 28 | -------------------------------------------------------------------------------- /sample/advent/twas-a-bit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | # twas-a-bit -- Generate a winter-holiday poem in the Mad Libs style 3 | 4 | defn main(): 5 | say: poem() 6 | 7 | data =: load('a-bit-of-data.ys') 8 | 9 | defn W(kind): 10 | rand-nth: get(data, name(kind)) 11 | 12 | defn poem(): | 13 | 'Twas a bit before $W(:holiday), and all through the $W(:place), 14 | not a creature was stirring, not even a $W(:animal). 15 | The stockings were hung by the $W(:hang-by) with care, 16 | In hopes that St. $W(:saint) soon would be there. 17 | The $W(:children) were nestled all snug in their $W(:beds), 18 | While visions of $W(:adj)-$W(:candies) danced in their heads. 19 | And $W(:relative) in their 'kerchief, and I in my $W(:hat), 20 | Had just settled down for a long winter's $W(:activity). 21 | When out on the $W(:outside) there arose such a clatter, 22 | I sprang from my $W(:seat) to see what was the matter. 23 | Away to the window, I flew like a $W(:flyer), 24 | Tore open the $W(:covers) and threw up the $W(:cover). 25 | The $W(:luminary) on the breast of the new-fallen $W(:fallers), 26 | Gave the lustre of mid-day to $W(:outers) below. 27 | When what to my wondering eyes should $W(:arrive)? 28 | But a miniature $W(:vehicle), and eight tiny $W(:service-animals). 29 | -------------------------------------------------------------------------------- /sample/blog/2024-03-25/an-example.yaml: -------------------------------------------------------------------------------- 1 | # Start in "data mode" 2 | !YS-v0: 3 | 4 | # This `::` preamble loads reusable data and code: 5 | :: 6 | # Set `vars` to an external data mapping: 7 | vars =: load('data.yaml') 8 | # Load a local custom YS library file that has a `rot13` function: 9 | load: "rot13.ys" 10 | 11 | 12 | # The rest of the file is normal YAML data. 13 | # It could have been a massive YAML file that we wanted to enhance. 14 | # The lines above lets us do that cleanly. 15 | # Now we can use `::` or `!` to switch to "code mode" at any point: 16 | 17 | some: plain string 18 | multi: ! | 19 | foo 20 | bar 21 | $(vars.name) 22 | person: 23 | name:: vars.name 24 | age:: 6 * vars.number 25 | encrypted pw:: vars.password.rot13() 26 | numbers:: 1 .. vars.number 27 | -------------------------------------------------------------------------------- /sample/blog/2024-03-25/data.yaml: -------------------------------------------------------------------------------- 1 | number: 7 2 | name: Bob 3 | password: s3cr3t 4 | -------------------------------------------------------------------------------- /sample/blog/2024-03-25/rot13.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn rot13(input): 4 | s =: set((\\A .. \\Z) + (\\a .. \\z)) 5 | cycle(s): .drop(13 * 2).zipmap(s).escape(input) 6 | -------------------------------------------------------------------------------- /sample/data.ys: -------------------------------------------------------------------------------- 1 | !YS-v0: 2 | 3 | foods:: load('./food.yaml') 4 | numbers:: 6 .. 9 5 | -------------------------------------------------------------------------------- /sample/food.yaml: -------------------------------------------------------------------------------- 1 | fruit: 2 | - apple 3 | - banana 4 | nuts: 5 | - cashew 6 | - drupe 7 | -------------------------------------------------------------------------------- /sample/github-issues/issue-12.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Written for https://github.com/yaml/yamlscript/issues/12 4 | # 5 | # Re: https://yamlscript.org/posts/advent-2023/dec-21/ 6 | # 7 | # Run the example Python program that loads a YAML file with embedded YS 8 | # commands. 9 | # 10 | # This script only assumes you have bash, python3 and curl 11 | # It installs a local libyamlscript.so library and yamlscript.py module. 12 | 13 | [[ $RERUN ]] || { RERUN=1 bash "$0" 2>&1 | tee "$0.txt"; exit; } 14 | 15 | set -euo pipefail 16 | 17 | set -x 18 | 19 | dir=${0%.sh} 20 | 21 | rm -fr "$dir" 22 | 23 | mkdir -p "$dir" 24 | 25 | cd "$dir" 26 | 27 | python3 -mvenv venv 28 | 29 | source venv/bin/activate &>/dev/null 30 | 31 | pip3 -q install yamlscript 32 | 33 | ( 34 | which python3 35 | pip3 show yamlscript | grep Version: 36 | ) 37 | 38 | prefix=$PWD/install 39 | 40 | curl https://yamlscript.org/install | PREFIX=$prefix bash 41 | 42 | ( 43 | tree install 44 | ) 45 | 46 | export LD_LIBRARY_PATH=$prefix/lib 47 | # for macos: 48 | export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH 49 | 50 | cat <<... > db.yaml 51 | cars: 52 | - make: Ford 53 | model: Mustang 54 | year: 1967 55 | color: red 56 | - make: Dodge 57 | model: Charger 58 | year: 1969 59 | color: orange 60 | - make: Chevrolet 61 | model: Camaro 62 | year: 1969 63 | color: blue 64 | ... 65 | 66 | cat <<... > racers.yaml 67 | !YS-v0: 68 | 69 | db =: load("db.yaml") 70 | 71 | - name: Ingy dot Net 72 | car: ! db.cars.0 73 | - name: Santa Claus 74 | car: ! db.cars.1 75 | - name: Sir Lancelot 76 | car: ! db.cars.2 77 | ... 78 | 79 | cat <<... > race-report.py 80 | #!/usr/bin/env python 81 | 82 | import yaml, yamlscript 83 | 84 | data = yamlscript.YAMLScript().load(open('racers.yaml')) 85 | 86 | print(yaml.dump(data)) 87 | ... 88 | 89 | python3 race-report.py 90 | -------------------------------------------------------------------------------- /sample/readme/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "readme" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | yamlscript = "0.1.2" 10 | -------------------------------------------------------------------------------- /sample/readme/file.ys: -------------------------------------------------------------------------------- 1 | !YS-v0: 2 | 3 | name =: 'World' 4 | 5 | foo: [1, 2, ! 6 * 7] 6 | bar:: load('other.yaml') 7 | baz:: "Hello, $name!" 8 | -------------------------------------------------------------------------------- /sample/readme/other.yaml: -------------------------------------------------------------------------------- 1 | oh: Hello 2 | -------------------------------------------------------------------------------- /sample/readme/prog.pl: -------------------------------------------------------------------------------- 1 | use YAMLScript; 2 | use JSON; 3 | my $ys = YAMLScript->new; 4 | my $input = do { local $/; open my $fh, '<', 'file.ys'; <$fh> }; 5 | my $data = $ys->load($input); 6 | print encode_json $data; 7 | -------------------------------------------------------------------------------- /sample/readme/prog.py: -------------------------------------------------------------------------------- 1 | from yamlscript import YAMLScript 2 | ys = YAMLScript() 3 | input = open('file.ys').read() 4 | data = ys.load(input) 5 | print(data) 6 | -------------------------------------------------------------------------------- /sample/readme/prog.raku: -------------------------------------------------------------------------------- 1 | use YAMLScript; 2 | my $program = slurp 'file.ys'; 3 | my YAMLScript $ys .= new; 4 | say $ys.load($program); 5 | -------------------------------------------------------------------------------- /sample/readme/prog.rb: -------------------------------------------------------------------------------- 1 | require 'yamlscript' 2 | input = IO.read('file.ys') 3 | ys = YAMLScript.new 4 | data = ys.load(input) 5 | puts data 6 | -------------------------------------------------------------------------------- /sample/readme/prog.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::prelude::*; 3 | use yamlscript::YAMLScript; 4 | 5 | fn main() -> std::io::Result<()> { 6 | let mut file = File::open("file.ys")?; 7 | let mut input = String::new(); 8 | file.read_to_string(&mut input)?; 9 | let ys = YAMLScript::new().unwrap(); 10 | let data = ys.load::(&input).unwrap(); 11 | println!("{data:?}"); 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /sample/readme/some.yaml: -------------------------------------------------------------------------------- 1 | food: 2 | fruit: 3 | - apple 4 | - banana 5 | - cherry 6 | - date 7 | 8 | hello: 9 | - Aloha 10 | - Bonjour 11 | - Ciao 12 | - Dzień dobry 13 | -------------------------------------------------------------------------------- /sample/readme/some.ys: -------------------------------------------------------------------------------- 1 | !YS-v0: 2 | 3 | :: 4 | name =: 'World' 5 | data =: load('some.yaml') 6 | fruit =: data.food.fruit 7 | 8 | num: 123 9 | greet:: "$(data.hello:rand-nth), $name!" 10 | eat:: fruit:shuffle:first 11 | drink:: (['Bar'] * 3).join(', ').str('!!!') 12 | -------------------------------------------------------------------------------- /sample/readme/ys-load.js: -------------------------------------------------------------------------------- 1 | let fs = require("fs"); 2 | let YS = require("@yaml/yamlscript"); 3 | 4 | let input = fs.readFileSync("some.ys", "utf8"); 5 | 6 | let ys = new YS(); 7 | 8 | let data = ys.load(input); 9 | 10 | console.log(data); 11 | -------------------------------------------------------------------------------- /sample/rosetta-code/100-doors.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(): 4 | say: |- 5 | Open doors after 100 passes: 6 | $(open-doors().join(', ')) 7 | 8 | defn open-doors(): 9 | ? for [d n] map(vector doors() range().drop(1)) 10 | :when d 11 | : n 12 | 13 | defn doors(): 14 | reduce: 15 | fn(doors idx): doors.assoc(idx true) 16 | into []: repeat(100 false) 17 | map \(sqr(_).--): 1 .. 10 18 | -------------------------------------------------------------------------------- /sample/rosetta-code/99-bottles-of-beer.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(number=99): 4 | :: Print the verses to "99 Bottles of Beer" 5 | each num (number .. 1): 6 | say: | 7 | $bottles(num) of beer on the wall, 8 | $bottles(num) of beer. 9 | Take one down, pass it around. 10 | $bottles(num.--) of beer on the wall. 11 | 12 | defn bottles(n): 13 | condp eq n: 14 | 0 :: No more bottles 15 | 1 :: 1 bottle 16 | else : "$n bottles" 17 | -------------------------------------------------------------------------------- /sample/rosetta-code/average-loop-length.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | # Use *' (vs. *) to allow arbitrary length arithmetic: 4 | mul =: value("*'") 5 | 6 | # Number of random times to test each n: 7 | TIMES =: 1000000 8 | 9 | defn main(max=20): 10 | say: "\tAvg\tExp\tDiff" 11 | 12 | doseq n (1 .. max): 13 | anal =: analytical(n):F 14 | avg =: avg-cycle-length(n TIMES):F 15 | diff =: abs(100 * (1 - (avg / anal))) 16 | say: 17 | format "%3d\t%.4f\t%.4f\t%.2f%%": n avg anal diff 18 | 19 | defn factorial(n): 20 | :: n! 21 | range(1 n.++): .mul(*) 22 | 23 | defn analytical(n): 24 | :: Analytical computation 25 | 1 .. n: 26 | .map(\(factorial(n) / pow(n _) / factorial(n - _))) 27 | .sum() 28 | 29 | defn single-test-cycle-length(n): 30 | :: Single random test of cycle length 31 | loop count 0, bits 0, x 1: 32 | if bit-and(x bits) == 0: 33 | recur: count.++ bit-or(bits x) bit-shift-left(1 rand-int(n)) 34 | else: count 35 | 36 | defn avg-cycle-length(n times): 37 | :: Average results of single tests of cycle lengths 38 | div _ times: 39 | sum: 40 | for i (range times): 41 | single-test-cycle-length: n 42 | -------------------------------------------------------------------------------- /sample/rosetta-code/factorial.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(n=10): 4 | say: "$n! -> $factorial(n)" 5 | 6 | defn factorial(x): 7 | 2 .. x: .mul(*) 8 | -------------------------------------------------------------------------------- /sample/rosetta-code/fibonacci-sequence.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(n=10): 4 | loop a 0, b 1, i 1: 5 | say: a 6 | when i < n: 7 | recur: b, (a + b), i.++ 8 | -------------------------------------------------------------------------------- /sample/rosetta-code/fizzbuzz.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(count=100 impl=1): 4 | :: | 5 | Invoke one of the FizzBuzz implementations below. 6 | 7 | usage: ys fizzbuzz.ys [ []] 8 | 9 | fizzbuzz =: "fizzbuzz-$impl" 10 | say: "Running function '$fizzbuzz' with count=$count" 11 | mapv say: 12 | call fizzbuzz: count 13 | 14 | defn fizzbuzz-1(n): 15 | :: Implementation 1 - with 'map' 16 | map _ (1 .. n): 17 | fn(x): 18 | cond: 19 | zero?(x % 15) : 'FizzBuzz' 20 | zero?(x % 5) : 'Buzz' 21 | zero?(x % 3) : 'Fizz' 22 | else : x 23 | 24 | defn fizzbuzz-2(n): 25 | :: Implementation 2 - with 'loop' 26 | loop i 1, l []: 27 | if i <= n: 28 | recur i.++: 29 | conj l: 30 | condp eq 0: 31 | i % 15 :: FizzBuzz 32 | i % 5 :: Buzz 33 | i % 3 :: Fizz 34 | else : i 35 | else: l 36 | 37 | defn fizzbuzz-3(n): 38 | :: Implementation 3 - with 'for' 39 | for x (1 .. n): str(((x % 3).! &&& 'Fizz') ((x % 5).! &&& 'Buzz')) ||| x 40 | -------------------------------------------------------------------------------- /sample/rosetta-code/floyds-triangle.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(n=14): 4 | nums =: range().map(inc).map(str) 5 | rows =: 6 | loop row-n 1, nums nums, rows []: 7 | if rows.# < n: 8 | recur: row-n.++ nums.drop(row-n) 9 | conj(rows nums.take(row-n)) 10 | else: rows 11 | width =: rows:last:last:len 12 | fmt =: \((' ' * (width - _:len)) + _) 13 | each row rows: say(row.map(fmt):joins) 14 | -------------------------------------------------------------------------------- /sample/rosetta-code/function-definition.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | # Main function definition with variable arguments: 4 | defn main(*args): 5 | say: "multiply($(args.join(', '))) 6 | -> $multiply(args*)" 7 | 8 | # A multi-arity function definition: 9 | defn multiply: 10 | (): 1 11 | (x): x 12 | (x y): x * y 13 | (x y *more): 14 | reduce multiply: 15 | multiply(x y) more 16 | -------------------------------------------------------------------------------- /sample/rosetta-code/greatest-common-divisor.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(a=42 b=63): 4 | say: "gcd($a $b) -> $gcd(a b)" 5 | 6 | defn gcd(a b): 7 | if b > 0: 8 | recur b: a % b 9 | else: a 10 | -------------------------------------------------------------------------------- /sample/rosetta-code/hello-world-text.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | say: "Hello, world!" 4 | 5 | =>: (say "Hello, world!") 6 | 7 | =>: say("Hello, world!") 8 | 9 | say: 10 | =>: "Hello, world!" 11 | 12 | say: ("Hello, " + "world!") 13 | 14 | say: ."Hello," "world!" 15 | 16 | say "Hello,": "world!" 17 | 18 | say "Hello," "world!": 19 | -------------------------------------------------------------------------------- /sample/rosetta-code/hello-world.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | say: 'Hello, world!' 4 | 5 | =>: (say 'Hello, world!') 6 | 7 | =>: say('Hello, world!') 8 | 9 | say: 10 | -'Hello, ' +: 'world!' 11 | 12 | say: -'Hello, ' + 'world!' 13 | 14 | say: -'Hello,' 'world!' 15 | 16 | say 'Hello,': 'world!' 17 | 18 | say 'Hello,' 'world!': 19 | -------------------------------------------------------------------------------- /sample/rosetta-code/leap-year.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(year=2024): 4 | say: "$year is $when-not( 5 | leap-year(year) 'not ')a 6 | leap year." 7 | 8 | defn leap-year(year): 9 | (year % 4) == 0 &&: 10 | (year % 100):pos? ||: 11 | (year % 400).eq(0) 12 | -------------------------------------------------------------------------------- /sample/rosetta-code/palindrome-detection.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(n=31337): 4 | not =: when((n:S != n:S:reverse) ' not') 5 | say: "$n is$not a palindrome." 6 | -------------------------------------------------------------------------------- /sample/rosetta-code/rot-13.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(input='Hello, World!'): 4 | s =: set(\\A .. \\Z) + (\\a .. \\z) 5 | say: cycle(s).drop(13 * 2) 6 | .zipmap(s).escape(input) 7 | -------------------------------------------------------------------------------- /sample/rosetta-code/sieve-of-eratosthenes.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(n=100): 4 | primes =: primes-up-to(n) 5 | say: |- 6 | The $(primes.#) prime numbers less than $n are: 7 | $(text(primes):chomp) 8 | 9 | defn primes-up-to(limit): 10 | :: Returns a lazy sequence of prime numbers less than limit. 11 | 12 | max-i =: int(limit.-- / 2) 13 | refs =: boolean-array(max-i true) 14 | root =: sqrt(limit):int.-- / 2 15 | ? doseq i (1 .. root) 16 | :when aget(refs i) 17 | : ? doseq 18 | j range( 19 | mul(i.++ 2 i), 20 | max-i, 21 | add(i i 1)) 22 | : aset(refs j false) 23 | cons 2: 24 | map \((_ * 2).++): 25 | filter \(aget refs _): 26 | range(1 max-i) 27 | -------------------------------------------------------------------------------- /sample/rosetta-code/weird-numbers.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn main(max=16500): 4 | weird =: sieve(max) 5 | numbers =: 6 | filter \(nth weird _): range(2 max 2) 7 | say: | 8 | The first $(numbers.#) weird numbers: 9 | $(numbers:joins) 10 | 11 | defn sieve(limit): 12 | weirds =: into([] repeat(limit true)) 13 | loop i 2, weirds weirds: 14 | if i < limit: 15 | recur (i + 2): 16 | or _ weirds: 17 | when weirds.$i: 18 | divs =: divisors(i) 19 | if abundant(i divs): 20 | when semiperfect(i divs): 21 | loop j i, weirds weirds: 22 | if j < limit: 23 | recur (j + i): 24 | weirds.assoc(j false) 25 | else: weirds 26 | weirds: .assoc(i false) 27 | else: weirds 28 | 29 | defn divisors(number): 30 | divisors =: 31 | mapcat _ range(1 sqrt(number)): 32 | fn(n): 33 | when 0 == (number % n): 34 | vector: n (number / n) 35 | divisors: .distinct().sort(gt _):rest 36 | 37 | defn abundant(n divs): 38 | sum(divs) > n 39 | 40 | defn semiperfect(n divs): 41 | when divs.# > 0: 42 | div *divs =: divs 43 | if n < div: 44 | semiperfect: n divs 45 | or: 46 | n ==: div 47 | semiperfect: (n - div) divs 48 | semiperfect: n divs 49 | -------------------------------------------------------------------------------- /sample/script.pl: -------------------------------------------------------------------------------- 1 | use strict; use warnings; 2 | use YAMLScript; 3 | use IO::All; 4 | use Data::Dumper qw(Dumper); 5 | $Data::Dumper::Indent = 1; 6 | $Data::Dumper::Terse = 1; 7 | 8 | my $ys = io('data.ys')->all; 9 | my $data = YAMLScript->new->load($ys); 10 | 11 | print Dumper($data); 12 | -------------------------------------------------------------------------------- /sample/www/db-config.yaml: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | base =: load('./db-defaults.yaml') 4 | # host: localhost 5 | # port: 12345 6 | # user: app 7 | # password: secret 8 | 9 | secret =: load('secret.yaml') 10 | # dev: devsecret 11 | # stage: stagesecret 12 | # prod: prodsecret 13 | 14 | data =:: 15 | development:: 16 | merge base:: 17 | user: dev 18 | password:: secret.dev 19 | 20 | staging:: 21 | merge base:: 22 | host: staging-db.myapp.com 23 | 24 | production:: 25 | merge base:: 26 | host: prod-db.myapp.com 27 | user: prod 28 | password:: secret.prod 29 | 30 | defn main(level='development'): 31 | get: data level 32 | -------------------------------------------------------------------------------- /sample/www/db-defaults.yaml: -------------------------------------------------------------------------------- 1 | host: localhost 2 | port: 12345 3 | user: app 4 | password: secret 5 | -------------------------------------------------------------------------------- /sample/www/example.py: -------------------------------------------------------------------------------- 1 | import yamlscript 2 | ys = yamlscript.YAMLScript() 3 | text = open("db-config.yaml").read() 4 | data = ys.load(text) 5 | -------------------------------------------------------------------------------- /sample/www/hello.ys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | defn main(name='world'): 4 | greet: name 5 | 6 | defn greet(name): 7 | say: "Hello, $name!" 8 | -------------------------------------------------------------------------------- /sample/www/secret.yaml: -------------------------------------------------------------------------------- 1 | dev: devsecret 2 | stage: stagesecret 3 | prod: prodsecret 4 | -------------------------------------------------------------------------------- /util/YSJ: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | ( 6 | libyamlscript_version=0.1.96 7 | root=$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/.." && pwd -P) 8 | JAVA_HOME=$(make -C "$root/core" env | grep ^JAVA_HOME= | cut -d= -f2) 9 | export JAVA_HOME 10 | export PATH=$JAVA_HOME/bin:$PATH 11 | root_ys=$root/ys 12 | jar=yamlscript.cli-$libyamlscript_version-SNAPSHOT-standalone.jar 13 | make --no-print-directory -C "$root_ys" jar 14 | java -jar "$root_ys/target/uberjar/$jar" "$@" 15 | ) 16 | -------------------------------------------------------------------------------- /util/copy-md: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | from=$1 to=$2 6 | 7 | temp=$(mktemp) 8 | trap 'rm -f $temp' exit 9 | 10 | cp "$from" "$temp" 11 | 12 | DNE='' 13 | 14 | perl -pi -e 's{^---\n\n}{---\n\n'"$DNE"'\n\n}m' "$temp" 15 | 16 | touch "$temp" 17 | 18 | mv "$temp" "$to" 19 | -------------------------------------------------------------------------------- /util/mdys-md: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | from=$1 to=$2 6 | 7 | temp=$(mktemp) 8 | trap 'rm -f $temp' exit 9 | 10 | mdys "$from" > "$temp" 11 | 12 | touch "$temp" 13 | 14 | [[ -s $temp ]] && mv "$temp" "$to" 15 | -------------------------------------------------------------------------------- /util/release-crystal: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | lang=crystal 4 | 5 | source "${YAMLSCRIPT_ROOT?}/util/release-repo.bash" 6 | 7 | update() ( 8 | ( 9 | cd "$repo_dir" || exit 10 | rm -fr \ 11 | examples \ 12 | spec \ 13 | src \ 14 | test 15 | ) 16 | 17 | cp "$root/License" "$repo_dir/LICENSE" 18 | 19 | ( 20 | cd "$from_dir" || exit 21 | cp ReadMe.md \ 22 | shard.yml \ 23 | "$repo_dir/" 24 | cp -r \ 25 | examples \ 26 | spec \ 27 | src \ 28 | test \ 29 | "$repo_dir/" 30 | ) 31 | ) 32 | 33 | main "$@" 34 | -------------------------------------------------------------------------------- /util/release-go: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | lang=go 4 | 5 | source "${YAMLSCRIPT_ROOT?}/util/release-repo.bash" 6 | 7 | update() ( 8 | cp "$root/License" "$repo_dir/LICENSE" 9 | 10 | ( 11 | cd "$from_dir" || exit 12 | cp \ 13 | ReadMe.md \ 14 | go.mod \ 15 | go.sum \ 16 | yamlscript.go \ 17 | "$repo_dir" 18 | ) 19 | 20 | perl -pi -e 's{yamlscript/go}{yamlscript-go}' \ 21 | "$repo_dir/go.mod" 22 | ) 23 | 24 | main "$@" 25 | -------------------------------------------------------------------------------- /util/release-repo.bash: -------------------------------------------------------------------------------- 1 | # shellcheck disable=2034,2154 2 | 3 | set -euo pipefail 4 | 5 | set -x 6 | 7 | root=$YAMLSCRIPT_ROOT 8 | version=$YS_RELEASE_VERSION_NEW 9 | 10 | main() ( 11 | init 12 | clone 13 | update 14 | release 15 | ) 16 | 17 | init() { 18 | repo_dir=$root/.git/tmp/yamlscript-$lang 19 | repo_url=git@github.com:yaml/yamlscript-$lang 20 | from_dir=$root/$lang 21 | } 22 | 23 | repo_url=git@github.com:yaml/yamlscript-$lang 24 | from_dir=$root/$lang 25 | 26 | clone() ( 27 | rm -fr "$repo_dir" 28 | git clone "$repo_url" "$repo_dir" 29 | ) 30 | 31 | release() ( 32 | cd "$repo_dir" || exit 33 | git add -A . 34 | git commit -m "Release $YS_RELEASE_VERSION_NEW" 35 | git push 36 | git tag "v$YS_RELEASE_VERSION_NEW" 37 | git push --tags 38 | ) 39 | 40 | true 41 | -------------------------------------------------------------------------------- /util/version-bump: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | ROOT =: ENV.ROOT || 4 | die("'ROOT' env var not defined") 5 | 6 | defn main(): 7 | plan =: load("$ROOT/.version.ys") 8 | 9 | each p plan: 10 | vers bump all =: p.slice(qw(vers bump all)) 11 | each b bump: 12 | regx file =: b.slice(qw(regx file)) 13 | regx =: qr(regx) 14 | each f file: 15 | f =: "$ROOT/$f" 16 | text =: f:read 17 | m =: re-matcher(regx text) 18 | if re-find(m): 19 | do: 20 | x m1 m2 =: re-groups(m) 21 | replace =: 22 | if all: 23 | str/replace 24 | str/replace-first 25 | write f: 26 | replace: 27 | text regx 28 | str/re-quote-replacement("$m1$vers$m2") 29 | say: "Bumped '$f'" 30 | warn: -['No Match!!' f regx] 31 | 32 | shell {:dir 'rust'}: 'cargo update' 33 | -------------------------------------------------------------------------------- /www/.gitignore: -------------------------------------------------------------------------------- 1 | /repo/ 2 | /site/ 3 | /.cache/ 4 | /.venv/ 5 | 6 | /mkdocs.yml 7 | /sample 8 | /material 9 | -------------------------------------------------------------------------------- /www/.vimrc: -------------------------------------------------------------------------------- 1 | set noswapfile 2 | -------------------------------------------------------------------------------- /www/config/about.yaml: -------------------------------------------------------------------------------- 1 | - About YS: doc/about.md 2 | - Features: doc/features.md 3 | 4 | # - Getting started: 5 | # # - Foo: doc/foo.md 6 | # - About YS: doc/intro.md 7 | # - YAML is YS: doc/yaml.md 8 | # - The ys Command: doc/cli.md 9 | # - YS YAML Loaders: doc/loaders.md 10 | # - Installation: doc/install.md 11 | 12 | # - Use Cases: 13 | # - Extending YAML: doc/extending.md 14 | # - YS Scripting: doc/scripting.md 15 | # - Query & Transform: doc/query.md 16 | -------------------------------------------------------------------------------- /www/config/blog-authors.yaml: -------------------------------------------------------------------------------- 1 | authors: 2 | ingydotnet: 3 | name: Ingy döt Net 4 | description: YAML Guy 5 | avatar: https://github.com/ingydotnet.png 6 | -------------------------------------------------------------------------------- /www/config/blog.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Try: https://liang2kl.github.io/mkdocs-blogging-plugin/ 3 | 4 | - blog/2024-11-29.md 5 | - blog/2024-11-05.md 6 | - blog/2024-07-17.md 7 | - Dr. StrangeYAML: blog/2024-06-20.md 8 | - Older: 9 | - blog/2024-04-16.md 10 | - blog/2024-03-14.md 11 | - 2023 Advent Posts: 12 | - blog/advent-2023/dec-24.md 13 | - blog/advent-2023/dec-23.md 14 | - blog/advent-2023/dec-22.md 15 | - blog/advent-2023/dec-21.md 16 | - blog/advent-2023/dec-20.md 17 | - blog/advent-2023/dec-19.md 18 | - blog/advent-2023/dec-18.md 19 | - blog/advent-2023/dec-17.md 20 | - blog/advent-2023/dec-16.md 21 | - blog/advent-2023/dec-15.md 22 | - blog/advent-2023/dec-14.md 23 | - blog/advent-2023/dec-13.md 24 | - blog/advent-2023/dec-12.md 25 | - blog/advent-2023/dec-11.md 26 | - blog/advent-2023/dec-10.md 27 | - blog/advent-2023/dec-09.md 28 | - blog/advent-2023/dec-08.md 29 | - blog/advent-2023/dec-07.md 30 | - blog/advent-2023/dec-06.md 31 | - blog/advent-2023/dec-05.md 32 | - blog/advent-2023/dec-04.md 33 | - blog/advent-2023/dec-03.md 34 | - blog/advent-2023/dec-02.md 35 | - blog/advent-2023/dec-01.md 36 | -------------------------------------------------------------------------------- /www/config/community.yaml: -------------------------------------------------------------------------------- 1 | - community/index.md 2 | 3 | - YS Social: social.md 4 | - Contributing to YS: 5 | - contrib/index.md 6 | - contrib-website.md 7 | -------------------------------------------------------------------------------- /www/config/doc.yaml: -------------------------------------------------------------------------------- 1 | - doc/index.md 2 | - doc/intro.md 3 | - doc/ys4yaml.md 4 | 5 | - Learn YS: 6 | - doc/exercism.md 7 | - doc/examples.md 8 | - doc/modes.md 9 | - doc/cheat.md 10 | - doc/vocab.md 11 | # - doc/4clojure.md 12 | - doc/clj-to-ys.md 13 | 14 | - Use YS: 15 | - doc/ys.md 16 | - doc/install.md 17 | - doc/env-vars.md 18 | - doc/loaders.md 19 | 20 | - YS Libraries: 21 | - doc/ys-std.md 22 | - doc/core.md 23 | - doc/ys-ys.md 24 | - doc/ys-yaml.md 25 | - doc/ys-json.md 26 | - doc/ys-csv.md 27 | - doc/ys-clj.md 28 | - doc/ys-taptest.md 29 | 30 | 31 | - YS Reference: 32 | - doc/yaml.md 33 | - doc/clojure.md 34 | - doc/yes.md 35 | - doc/modes.md 36 | - doc/control.md 37 | - doc/operators.md 38 | - doc/chain.md 39 | - YS Unit Testing: doc/ys-taptest.md 40 | 41 | - More YS Topics: 42 | - doc/v0.md 43 | - doc/binary.md 44 | - doc/run-ys.md 45 | 46 | 47 | ### 48 | # - Tutorials: 49 | # - Writing YS Modules: doc/modules.md 50 | 51 | # - Overview: docs/overview.md 52 | # - Configuration: docs/configuration.md 53 | # - Usage: docs/usage.md 54 | # - Examples: docs/examples.md 55 | # - Contributing: docs/contributing.md 56 | # - Changelog: docs/changelog.md 57 | 58 | # - Gallery: 59 | # - YS for YAML Users: doc/yaml.md 60 | # - YS on Exercism: doc/exercism.md 61 | # - YS on Rosetta Code: doc/rosetta.md 62 | # - YS for Jsonnet Users: doc/jsonnet.md 63 | # - YS for Cue Users: doc/cue.md 64 | # - YS for HCL Users: doc/hcl.md 65 | # - YS for Jinja2 Users: doc/jinja2.md 66 | # - YS for Python Programmers: doc/python.md 67 | # - YS for Clojure Programmers: doc/clojure.md 68 | -------------------------------------------------------------------------------- /www/config/learn.yaml: -------------------------------------------------------------------------------- 1 | 2 | - Learn YS: doc/learn.md 3 | - YS by Example: doc/examples.md 4 | - YS Cheat Sheet: doc/cheat.md 5 | -------------------------------------------------------------------------------- /www/config/press.yaml: -------------------------------------------------------------------------------- 1 | press.yaml 2 | -------------------------------------------------------------------------------- /www/config/redirect.yaml: -------------------------------------------------------------------------------- 1 | doc/helmys.md: helmys.md 2 | 3 | # Blog posts from old site: 4 | posts/2024-11-29.md: blog/posts/2024-11-29.md 5 | posts/2024-11-05.md: blog/posts/2024-11-05.md 6 | posts/2024-07-17.md: blog/posts/2024-07-17.md 7 | posts/2024-06-20.md: blog/posts/2024-06-20.md 8 | posts/2024-04-16.md: blog/posts/2024-04-16.md 9 | posts/2024-03-14.md: blog/posts/2024-03-14.md 10 | posts/advent-2023/dec-24.md: blog/posts/2023-12-24.md 11 | posts/advent-2023/dec-23.md: blog/posts/2023-12-23.md 12 | posts/advent-2023/dec-22.md: blog/posts/2023-12-22.md 13 | posts/advent-2023/dec-21.md: blog/posts/2023-12-21.md 14 | posts/advent-2023/dec-20.md: blog/posts/2023-12-20.md 15 | posts/advent-2023/dec-19.md: blog/posts/2023-12-19.md 16 | posts/advent-2023/dec-18.md: blog/posts/2023-12-18.md 17 | posts/advent-2023/dec-17.md: blog/posts/2023-12-17.md 18 | posts/advent-2023/dec-16.md: blog/posts/2023-12-16.md 19 | posts/advent-2023/dec-15.md: blog/posts/2023-12-15.md 20 | posts/advent-2023/dec-14.md: blog/posts/2023-12-14.md 21 | posts/advent-2023/dec-13.md: blog/posts/2023-12-13.md 22 | posts/advent-2023/dec-12.md: blog/posts/2023-12-12.md 23 | posts/advent-2023/dec-11.md: blog/posts/2023-12-11.md 24 | posts/advent-2023/dec-10.md: blog/posts/2023-12-10.md 25 | posts/advent-2023/dec-09.md: blog/posts/2023-12-09.md 26 | posts/advent-2023/dec-08.md: blog/posts/2023-12-08.md 27 | posts/advent-2023/dec-07.md: blog/posts/2023-12-07.md 28 | posts/advent-2023/dec-06.md: blog/posts/2023-12-06.md 29 | posts/advent-2023/dec-05.md: blog/posts/2023-12-05.md 30 | posts/advent-2023/dec-04.md: blog/posts/2023-12-04.md 31 | posts/advent-2023/dec-03.md: blog/posts/2023-12-03.md 32 | posts/advent-2023/dec-02.md: blog/posts/2023-12-02.md 33 | posts/advent-2023/dec-01.md: blog/posts/2023-12-01.md 34 | -------------------------------------------------------------------------------- /www/config/start.yaml: -------------------------------------------------------------------------------- 1 | - foo.md 2 | -------------------------------------------------------------------------------- /www/config/theme.yaml: -------------------------------------------------------------------------------- 1 | !YS-v0: 2 | 3 | # See: https://github.com/squidfunk/mkdocs-material/discussions/3406 4 | # for info on template overrides. 5 | # Template source: 6 | # https://github.com/squidfunk/mkdocs-material/tree/master/material/templates 7 | 8 | name: material 9 | 10 | custom_dir: theme 11 | 12 | # * For dark themed code blocks 13 | # See: https://github.com/squidfunk/mkdocs-material/issues/768 14 | 15 | features: 16 | - content.action.edit 17 | - content.action.view 18 | - content.code.copy 19 | - header.autohide 20 | - navigation.expand 21 | - navigation.footer 22 | - navigation.indexes 23 | - navigation.tabs 24 | 25 | # - navigation.instant # For single page application 26 | 27 | logo-image =: 'image/yamlscript-logo.svg' 28 | 29 | logo:: logo-image 30 | favicon:: logo-image 31 | 32 | palette: 33 | - scheme: default 34 | primary: custom 35 | toggle: 36 | icon: material/weather-night 37 | name: Switch to dark mode 38 | 39 | - scheme: slate 40 | primary: custom 41 | toggle: 42 | icon: material/weather-sunny 43 | name: Switch to light mode 44 | 45 | icon: 46 | edit: material/pencil 47 | view: material/eye 48 | talk: material/chat-question 49 | admonition: 50 | abstract: fontawesome/solid/book 51 | bug: fontawesome/solid/robot 52 | danger: fontawesome/solid/skull 53 | example: fontawesome/solid/flask 54 | failure: fontawesome/solid/bomb 55 | info: fontawesome/solid/circle-info 56 | note: octicons/note-16 57 | question: fontawesome/solid/circle-question 58 | quote: fontawesome/solid/quote-left 59 | success: fontawesome/solid/check 60 | tip: fontawesome/solid/bullhorn 61 | warning: fontawesome/solid/triangle-exclamation 62 | -------------------------------------------------------------------------------- /www/config/use.yaml: -------------------------------------------------------------------------------- 1 | - use/index.md 2 | 3 | - doc/query.md 4 | 5 | - DevOps: 6 | - helmys.md 7 | 8 | - CI/CD: 9 | - cicd.md 10 | - gha.md 11 | - circleci.md 12 | 13 | # - Static Site Generators: 14 | # - This site 15 | 16 | - Hacks: 17 | - hacks.md 18 | - gist.md 19 | - yamllm.md 20 | # - sbs.md 21 | 22 | # - hacks/index.md: 23 | # - yamllm.md 24 | # - mdys.md 25 | # - siteys.md 26 | # - sbs.md 27 | # - gist.md 28 | # - gmail.md 29 | -------------------------------------------------------------------------------- /www/requirements.txt: -------------------------------------------------------------------------------- 1 | babel==2.16.0 2 | bracex==2.5.post1 3 | cairosvg==2.7.1 4 | certifi==2024.12.14 5 | charset-normalizer==3.4.1 6 | click==8.1.8 7 | colorama==0.4.6 8 | ghp-import==2.1.0 9 | hjson==3.1.0 10 | idna==3.10 11 | Jinja2==3.1.6 12 | Markdown==3.7 13 | MarkupSafe==3.0.2 14 | mergedeep==1.3.4 15 | mkdocs==1.6.1 16 | mkdocs-awesome-pages-plugin==2.10.1 17 | mkdocs-get-deps==0.2.0 18 | mkdocs-link-marker==0.1.3 19 | mkdocs-macros-plugin==1.3.7 20 | mkdocs-material==9.5.50 21 | mkdocs-material-extensions==1.3.1 22 | mkdocs-open-in-new-tab==1.0.8 23 | mkdocs-redirects==1.2.2 24 | mkdocs-rss-plugin==1.17.1 25 | natsort==8.4.0 26 | packaging==24.2 27 | paginate==0.5.7 28 | pathspec==0.12.1 29 | pillow==11.1.0 30 | platformdirs==4.3.6 31 | Pygments==2.19.1 32 | pymdown-extensions==10.14 33 | python-dateutil==2.9.0.post0 34 | PyYAML==6.0.2 35 | pyyaml_env_tag==0.1 36 | regex==2024.11.6 37 | requests==2.32.3 38 | six==1.17.0 39 | super_collections==0.5.3 40 | termcolor==2.5.0 41 | urllib3==2.3.0 42 | watchdog==6.0.0 43 | wcmatch==10.0 44 | -------------------------------------------------------------------------------- /www/src/.gitignore: -------------------------------------------------------------------------------- 1 | /*.md 2 | /blog/*.md 3 | /blog/**/*.md 4 | /doc/*.md 5 | -------------------------------------------------------------------------------- /www/src/blog/.authors.yml: -------------------------------------------------------------------------------- 1 | authors: 2 | ingydotnet: 3 | name: Ingy döt Net 4 | description: YAML / YS Creator 5 | avatar: https://avatars.githubusercontent.com/u/21826 6 | url: https://github.com/ingydotnet 7 | -------------------------------------------------------------------------------- /www/src/blog/index.md: -------------------------------------------------------------------------------- 1 | 2 | !!! rss inline end "[RSS Feed](/rss.xml){target="_blank"}" 3 | 4 | # The YS Blog 5 | -------------------------------------------------------------------------------- /www/src/community/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Community 3 | talk: 0 4 | --- 5 | 6 | YS is a community-driven, Open Source Programming Language, with a focus on 7 | making YAML better everywhere. 8 | 9 | While YS is a "full" programming language, it is far from complete. 10 | There's so much interesting stuff to work on. 11 | We welcome your participation and contributions. 12 | 13 | Here are some ways you can get involved: 14 | 15 | * [Be Social](../social.md) 16 | * [Improve the Docs](../doc/index.md) 17 | * [Contribute to YS](../contrib/index.md) 18 | -------------------------------------------------------------------------------- /www/src/contrib-roadmap.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The YS Road Map 3 | talk: 0 4 | --- 5 | 6 | While the YS language is quite capable today for both extending YAML files and 7 | general programming, there is still a seemingly endless list of things that 8 | should be done to improve the language, its libraries, and full integration with 9 | with the world of data and code. 10 | 11 | 12 | ## YS Language Bindings 13 | 14 | 15 | YS YAML loaders have major advantages over the existing YAML loaders: 16 | 17 | * Same API and capabilities regardless of the language. 18 | * T 19 | * Highly configurable. 20 | -------------------------------------------------------------------------------- /www/src/contrib-rules.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contribution Guidelines 3 | talk: 0 4 | --- 5 | 6 | ## Please and Thank You 7 | 8 | YS is an Open Source project, and we need your help! 9 | 10 | 11 | -------------------------------------------------------------------------------- /www/src/font/AlexBrush-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaml/yamlscript/b47d953d40bb3dec8065e1fed45eb531b1acad0a/www/src/font/AlexBrush-Regular.woff -------------------------------------------------------------------------------- /www/src/gha.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS and GitHub Actions 3 | talk: 0 4 | --- 5 | 6 | [RapidYAML](https://rapidyaml.readthedocs.io/latest/) is the world's fastest and 7 | most correct YAML parser written in C++. 8 | 9 | It uses [GitHub Actions (GHA)](https://github.com/features/actions) workflows to 10 | build and test the codebase for a variety of platforms and configurations. 11 | 12 | The YAML files for these workflows are have been [converted to YS]( 13 | https://github.com/biojppm/rapidyaml/tree/master/.github/workflows-in) 14 | resulting in a much more concise, maintainable and readable set of workflows 15 | files (that do exactly the same thing as before). 16 | 17 | GitHub Actions is a really well thought out system for using YAML as a language 18 | to define CI/CD workflows. 19 | That said, YS can be used to make these workflows cleaner and more enjoyable to 20 | work with. 21 | 22 | 23 | !!! note "RapidYAML coming to YS Soon" 24 | 25 | The YS and RapidYAML authors have been working together to bring the power of 26 | RapidYAML to the YS compiler. 27 | Currently the YS compiler uses [SnakeYAML Engine]( 28 | https://bitbucket.org/asomov/snakeyaml-engine) (which is quite good) for its 29 | parsing stage. 30 | We hope that by offering RapidYAML as an option, we can make YS even faster and 31 | more correct. 32 | -------------------------------------------------------------------------------- /www/src/hacks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Hacks 3 | talk: 0 4 | --- 5 | 6 | 7 | Here are some interesting real-world hacks that have been done with YS. 8 | 9 | * [GitHub Gist](gist.md) — Post GitHub Gists from the command line. 10 | * [YAMLLM](yamllm.md) — a command line tool to query common LLM APIs. 11 | -------------------------------------------------------------------------------- /www/src/image/external-link.svg: -------------------------------------------------------------------------------- 1 | 3 | External link 4 | 7 | -------------------------------------------------------------------------------- /www/src/image/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaml/yamlscript/b47d953d40bb3dec8065e1fed45eb531b1acad0a/www/src/image/favicon.ico -------------------------------------------------------------------------------- /www/src/image/yamlscript-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/src/ingydotnet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About Ingy döt Net 3 | talk: 0 4 | --- 5 | 6 | Ingy döt Net is a software developer and speaker. 7 | He is best known for his work on the [YAML]( 8 | https://yaml.org/) data serialization language. 9 | 10 | Recently Ingy created the YS programming language, which embeds cleanly into 11 | YAML, adding the functional features that many YAML users need. 12 | 13 | 14 | ## Contact Ingy 15 | 16 | * Email: 17 | * LinkedIn: 18 | * GitHub: 19 | * Matrix: (best way to chat w/ Ingy) 20 | * Slack: 21 | * BlueSky: 22 | * Mastodon: 23 | 24 | 25 | ## Hire Ingy 26 | 27 | [Ingy](https://yamlscript.org/ingydotnet) is available for consulting, 28 | training, and speaking engagements worldwide on YS, YAML, and other related 29 | topics. 30 | -------------------------------------------------------------------------------- /www/src/install-libyamlscript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat <<... 4 | 5 | -------------------------------------------------------------------------------- 6 | ERROR: 'install-libyamlscript' has been renamed to 'install'. 7 | 8 | Use: 9 | 10 | curl https://yamlscript.org/install | LIB=1 bash 11 | -------------------------------------------------------------------------------- 12 | 13 | ... 14 | -------------------------------------------------------------------------------- /www/src/install-ys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat <<... 4 | 5 | -------------------------------------------------------------------------------- 6 | ERROR: 'install-ys' has been renamed to 'install'. 7 | 8 | Use: 9 | 10 | curl https://yamlscript.org/install | BIN=1 bash 11 | -------------------------------------------------------------------------------- 12 | 13 | ... 14 | -------------------------------------------------------------------------------- /www/src/json.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JSON is YAML! 3 | talk: 0 4 | --- 5 | 6 | Since [YAML 1.2](https://yaml.org/spec/1.2/spec.html) (2009) JSON is a complete 7 | subset of YAML. 8 | This means that any valid JSON file is also a valid YAML file and can be loaded 9 | by a YAML loader to produce the equivalent data structure as if it were loaded 10 | by a JSON parser. 11 | 12 | Since YS is a YAML loader it can used on JSON files as well. 13 | 14 | This is very useful for converting between the two formats and for using YS to 15 | [query and transform](doc/query.md) JSON files. 16 | 17 | 18 | !!! note 19 | 20 | Just because the YAML spec says it's a subset doesn't mean that all YAML 21 | tools can be trusted to handle JSON files 100% correctly. 22 | Caveat emptor. 23 | -------------------------------------------------------------------------------- /www/src/mdys.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | defn mdys-question(text, marker='???+'): 4 | m =: 5 | text =~ /^(.*)\n\n((?s:\S.+))/ ||: 6 | die: "Invalid content for mdys::question:\n$text" 7 | X question answer =: m 8 | 9 | =>: | 10 | $marker question "$question" 11 | 12 | $(answer.indent(4)) 13 | 14 | defn mdys-question-expand(text): 15 | mdys-question: text, '???' 16 | -------------------------------------------------------------------------------- /www/src/play.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Playing with YS 3 | talk: 0 4 | hide: 5 | - toc 6 | --- 7 | 8 | ## Coming Soon! 9 | 10 | We are working on a fun and interactive way to play with YS. Stay tuned! 11 | -------------------------------------------------------------------------------- /www/src/press.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Press 3 | talk: 0 4 | hide: 5 | - navigation 6 | --- 7 | 8 | 9 | ## YS in the News 10 | 11 | * [YS Releases](https://github.com/yaml/yamlscript/releases) 12 | * [YAML Becomes a Proper Programming Language]( 13 | https://thenewstack.io/with-yamlscript-yaml-becomes-a-proper-programming-language/) 14 | 15 | ## PodCasts 16 | 17 | * [Dead Code — February 11, 2025]( 18 | https://shows.acast.com/dead-code/episodes/yet-another-podcast-episode-with-ingy-dot-net) 19 | * [The REPL — April 15, 2024](https://www.therepl.net/episodes/52/) 20 | 21 | 22 | 23 | ## Presentation Videos 24 | 25 | * [Tutorial: Simplify and Optimize Your YAML with YAMLScript]( 26 | https://www.youtube.com/watch?v=Cdi3Q4Wrt48) -- 27 | Ingy's tutorial at KubeCon 2024 in Salt Lake City 28 | * [YAMLScript - Scripting in YAML]( 29 | https://www.youtube.com/watch?v=RFIukRdFe1o) -- 30 | Ingy at the 2024 TPRC in Las Vegas 31 | * [YAML and YAMLScript](https://www.youtube.com/watch?v=u-OCEHNdwlU) -- 32 | Ingy at Open Source Summit North America 2024 in Seattle 33 | * [Seajure March 2024 - YAMLScript]( 34 | https://www.youtube.com/watch?v=GajOBwBcFyA) 35 | 36 | 41 | -------------------------------------------------------------------------------- /www/src/site-testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Nothing to see here... 3 | --- 4 | 5 | * [Social Card for main page](/assets/images/social/index.png) 6 | -------------------------------------------------------------------------------- /www/src/social.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Social YS 3 | talk: 0 4 | --- 5 | 6 | Here are some places where you can engage with the YS Community: 7 | 8 | * [YS GitHub Discussions]( 9 | https://github.com/yaml/yamlscript/discussions) 10 | * [YS Matrix Chat](https://matrix.to/#/#chat-yamlscript:yaml.io) 11 | * [YS in Clojurians Slack](https://clojurians.slack.com/archives/yamlscript) 12 | * [YS on IRC](https://web.libera.chat/#yamlscript) 13 | -------------------------------------------------------------------------------- /www/src/try-ys: -------------------------------------------------------------------------------- 1 | # Note: Bash and Zsh supported but using bash for shellcheck here. 2 | # shellcheck shell=bash 3 | 4 | _yamlscript-try-ys() { 5 | local tmp dir 6 | tmp=${TMPDIR:-/tmp} 7 | tmp=${tmp%/} 8 | dir=$(mktemp -d "$tmp/yamlscript-try-ys-XXXXXXXXXX") && 9 | curl https://yamlscript.org/install | BIN=1 PREFIX=$dir bash && 10 | export PATH=$dir/bin:$PATH 11 | } 12 | 13 | _yamlscript-try-ys 14 | 15 | unset -f _yamlscript-try-ys 16 | 17 | cat <<'...' 18 | 19 | Try out these commands: 20 | 21 | ys --help 22 | 23 | ys -e 'each [i (1 .. 5)]: say("Hello!")' 24 | 25 | ys -e 'each [i (1 .. 5)]:' -e ' say: "Hello!"' 26 | ys -e 'each [i (1 .. 5)]:' -e ' say: "Hello!"' --compile 27 | ys -e 'each [i (1 .. 5)]:' -e ' say: "Hello!"' --load 28 | 29 | curl https://yamlscript.org/try/99-bottles.ys | ys - 3 30 | curl https://yamlscript.org/try/99-bottles.ys | ys - -c -X 31 | 32 | For more information about YS and `ys`: 33 | 34 | * https://github.com/yaml/yamlscript#readme 35 | * https://yamlscript.org/ 36 | * https://yamlscript.org/blog/ 37 | 38 | ... 39 | -------------------------------------------------------------------------------- /www/src/use/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: YS Use Cases 3 | talk: 0 4 | --- 5 | 6 | The primary goal of the YS project is to make YAML be able to do more. 7 | 8 | While the original goal of YAML was to be a human readable data serialization 9 | language, YAML has found its place in the world primarily as a software 10 | configuration language. 11 | 12 | YS has a strong focus on making YAML as good as possible for configuration. 13 | That said, YS is a complete, general purpose, functional programming language, 14 | that builds on top of the success of YAML, JSON, Clojure, Java and other 15 | technologies. 16 | It embeds perfectly into your YAML files, enabling almost any need you might 17 | have there, but it it also stands on its own in many other contexts. 18 | 19 | Check back here for more use cases as we add them. 20 | 21 | We hope you will find lots of excellent uses for YS. 22 | If you discover use cases that we haven't thought of, please let us know! 23 | We'll showcase them here. 24 | 25 | 26 | 53 | -------------------------------------------------------------------------------- /www/theme/ReadMe.md: -------------------------------------------------------------------------------- 1 | Files here are overrides from: 2 | https://github.com/squidfunk/mkdocs-material/tree/9.5.50/material 3 | -------------------------------------------------------------------------------- /www/theme/main.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block analytics %} 4 | 5 | 11 | 12 | {{ super() }} 13 | {% endblock %} 14 | 15 | {% block header %} 16 | 17 | 19 | 20 | {{ super() }} 21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /www/theme/partials/copyright.html: -------------------------------------------------------------------------------- 1 | {#- 2 | This file was automatically generated - do not edit 3 | -#} 4 | 18 | -------------------------------------------------------------------------------- /ys/.gitignore: -------------------------------------------------------------------------------- 1 | /.bpan/ 2 | /bin/ 3 | /lib/ 4 | -------------------------------------------------------------------------------- /ys/Makefile: -------------------------------------------------------------------------------- 1 | include ../common/base.mk 2 | include $(COMMON)/java.mk 3 | include $(COMMON)/clojure.mk 4 | include $(COMMON)/native.mk 5 | include $(COMMON)/vars-cli.mk 6 | 7 | BPAN_LOCAL := .bpan 8 | BPAN_REPO_URL := https://github.com/bpan-org/bpan 9 | 10 | test := test/ 11 | 12 | 13 | #------------------------------------------------------------------------------ 14 | build:: $(CLI_DEPS) 15 | 16 | install: $(CLI_DEPS) 17 | mkdir -p $(PREFIX)/bin 18 | install -m 755 $(CLI_BIN) $(PREFIX)/bin/ 19 | ln -fs $(notdir $(CLI_BIN)) \ 20 | $(PREFIX)/$(CLI_BIN:%-$(YS_VERSION)=%-$(API_VERSION)) 21 | ln -fs $(notdir $(CLI_BIN)) \ 22 | $(PREFIX)/$(CLI_BIN:%-$(YS_VERSION)=%) 23 | install -m 755 $(CLI_BIN_BASH) \ 24 | $(PREFIX)/bin/ 25 | 26 | jar: $(CLI_JAR) 27 | 28 | test: test-run 29 | 30 | test-all: test-unit test-run 31 | 32 | test-unit: $(CORE_INSTALLED) 33 | $(LEIN) test $(lein-test) 34 | 35 | test-run: $(CLI_DEPS) $(BPAN_LOCAL) 36 | prove $${TEST_VERBOSE:+'-v'} $(test) 37 | 38 | repl-deps:: $(CORE_INSTALLED) 39 | 40 | clean:: 41 | $(RM) -r .cpcache/ 42 | 43 | realclean:: 44 | $(RM) -r bin lib $(BPAN_LOCAL) 45 | 46 | $(BPAN_LOCAL): 47 | git clone --depth=1 $(BPAN_REPO_URL) $@ 48 | 49 | $(CLI_BIN): $(CLI_JAR) 50 | ifneq (true,$(LIBZ)) 51 | $(error *** \ 52 | The 'libz.$(SO)' library is required by native-image but not installed) 53 | endif 54 | mkdir -p $(dir $@) 55 | $(TIME) \ 56 | native-image \ 57 | -H:ConfigurationFileDirectories=config/ \ 58 | $(NATIVE_OPTS) \ 59 | \ 60 | -jar $< \ 61 | -o $@ 62 | ln -fs $(notdir $@) $(@:%-$(YS_VERSION)=%-$(API_VERSION)) 63 | ln -fs $(notdir $@) $(@:%-$(YS_VERSION)=%) 64 | touch $@ 65 | 66 | $(CLI_BIN_BASH): $(CLI_BIN_BASH_SRC) 67 | mkdir -p $(dir $@) 68 | cp $< $@ 69 | chmod 755 $@ 70 | 71 | $(CLI_JAR): $(CLI_JAR_DEPS) 72 | $(LEIN) uberjar 73 | touch $@ 74 | 75 | $(CORE_INSTALLED): $(CORE_JAR) 76 | $(MAKE) -C $(CORE_DIR) $@ 77 | 78 | $(CORE_JAR): $(CORE_DEPS) 79 | $(MAKE) -C $(CORE_DIR) $@ 80 | -------------------------------------------------------------------------------- /ys/deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources" "target/classes"], 2 | :deps 3 | {org.clojure/clojure {:mvn/version "1.12.0"}, 4 | org.clojure/core.async {:mvn/version "1.6.681"}, 5 | org.clojure/data.csv {:mvn/version "1.1.0"}, 6 | org.clojure/data.json {:mvn/version "2.4.0"}, 7 | org.clojure/tools.cli {:mvn/version "1.0.219"}, 8 | org.babashka/sci {:mvn/version "0.8.41"}, 9 | babashka/process {:mvn/version "0.5.21"}, 10 | clj-commons/clj-yaml {:mvn/version "1.0.27"}, 11 | yamlscript/core {:mvn/version "0.1.96"}}, 12 | :aliases 13 | {:lein2deps 14 | {:deps 15 | {io.github.borkdude/lein2deps 16 | {:git/sha "1bcf2fbbcbef611381e5e9ccdc77bec1e62ea5e5"}}, 17 | :ns-default lein2deps.build, 18 | :lein2deps/compile-java 19 | {:src-dirs ["src"], :class-dir "target/classes"}}}, 20 | :deps/prep-lib 21 | {:ensure "target/classes", :alias :lein2deps, :fn compile-java}, 22 | :mvn/repos {"public-github" {:url "git://github.com"}}} 23 | -------------------------------------------------------------------------------- /ys/reflection.json: -------------------------------------------------------------------------------- 1 | ../common/reflection.json -------------------------------------------------------------------------------- /ys/test/a-symlink: -------------------------------------------------------------------------------- 1 | dummy -------------------------------------------------------------------------------- /ys/test/advent.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | AV =: "$DIR/../../sample/advent" 6 | 7 | w =: /\w+/ 8 | 9 | 10 | test:: 11 | - name: ys silly.ys 12 | cmnd:: "ys $AV/silly.ys" 13 | like: \w+.*,.*\w+ 14 | 15 | - name: ys twas-a-bit 16 | cmnd:: "ys $AV/twas-a-bit" 17 | have: Twas a bit before 18 | 19 | - name: ys -p hearsay.ys 20 | cmnd:: "ys -p $AV/hearsay.ys" 21 | like: I heard that @\S+ uses YS in their \w+ code! 22 | 23 | - name: ys lol.ys 24 | cmnd:: "ys $AV/lol.ys" 25 | want: "1\n2\n3\n" 26 | 27 | - name: ys -Y grocery.yaml 28 | cmnd:: "ys -Y $AV/grocery.yaml" 29 | want: | 30 | - bread 31 | - fruits: 32 | - apple 33 | - banana 34 | - cherry 35 | - milk 36 | 37 | - name: ys tree.ys 38 | cmnd:: "ys $AV/tree.ys" 39 | want: |2+ 40 | * 41 | *** 42 | ***** 43 | ******* 44 | ********* 45 | * 46 | * 47 | 48 | - name: ys tree.ys 7 49 | cmnd:: "ys $AV/tree.ys 7" 50 | want: |2+ 51 | * 52 | *** 53 | ***** 54 | ******* 55 | ********* 56 | *********** 57 | ************* 58 | * 59 | * 60 | 61 | - name: ys madlibs 62 | cmnd:: "ys $AV/madlibs" 63 | like:: | 64 | Dear $w+, 65 | 66 | You should go to $w+( $w+)?. 67 | I really think you would $w+ it there. 68 | 69 | Sincerely, $w+ 70 | 71 | 72 | - cmnd: "ys -le 'map inc: range(1, 10)'" 73 | want: "[2,3,4,5,6,7,8,9,10]" 74 | 75 | - cmnd: "ys -le 'map inc:' -e ' range: 1, 10'" 76 | want: "[2,3,4,5,6,7,8,9,10]" 77 | 78 | - cmnd: "ys -le '=>: map(inc, range(1, 10))'" 79 | want: "[2,3,4,5,6,7,8,9,10]" 80 | 81 | - cmnd: "ys -le '->>: range(1, 10), map(inc)'" 82 | want: "[2,3,4,5,6,7,8,9,10]" 83 | 84 | - name: Interpolation example 85 | code: | 86 | name =: 'World' 87 | say: "Hello $name. The answer is $(43 - 1)." 88 | what: out 89 | want: Hello World. The answer is 42. 90 | 91 | done: 92 | -------------------------------------------------------------------------------- /ys/test/animals.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Meowsy", 4 | "species" : "cat", 5 | "foods": { 6 | "likes": ["tuna", "catnip"], 7 | "dislikes": ["ham", "zucchini"] 8 | } 9 | }, 10 | { 11 | "name": "Barky", 12 | "species" : "dog", 13 | "foods": { 14 | "likes": ["bones", "carrots"], 15 | "dislikes": ["tuna"] 16 | } 17 | }, 18 | { 19 | "name": "Purrpaws", 20 | "species" : "cat", 21 | "foods": { 22 | "likes": ["mice"], 23 | "dislikes": ["cookies"] 24 | } 25 | } 26 | ] -------------------------------------------------------------------------------- /ys/test/chain.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | hash =:: 6 | FOO: 1 7 | FOO_BAR: 2 8 | 9 | test:: 10 | - code: hash.FOO:B 11 | - code: hash.FOO_BAR:B 12 | 13 | - code: (1 .. 5).map(\(_:inc)) 14 | want: [2, 3, 4, 5, 6] 15 | 16 | done: 3 17 | -------------------------------------------------------------------------------- /ys/test/defn.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | test:: 6 | - name: Private function 7 | code: | 8 | defn foo(x): bar(x) + 1 9 | defn- bar(x): x * 2 10 | foo: 7 11 | want: 15 12 | 13 | done: 14 | -------------------------------------------------------------------------------- /ys/test/dot.ys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | NIL =: nil 6 | 7 | test:: 8 | - note: "Dot chain testing" 9 | 10 | - code: nil.$NIL 11 | want: null 12 | - code: nil.123 13 | want: null 14 | - code: nil.foo 15 | want: null 16 | - code: -{}.$NIL 17 | want: null 18 | - code: -[].$NIL 19 | want: null 20 | - code: true.foo 21 | want: null 22 | - code: -"foo".foo 23 | want: null 24 | 25 | - code: (1 .. 20).partition(3 5) 26 | want:: \'((1 2 3) (6 7 8) (11 12 13) (16 17 18)) 27 | 28 | done: 29 | -------------------------------------------------------------------------------- /ys/test/empty-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaml/yamlscript/b47d953d40bb3dec8065e1fed45eb531b1acad0a/ys/test/empty-file -------------------------------------------------------------------------------- /ys/test/hello-world.ys: -------------------------------------------------------------------------------- 1 | !YS-v0 2 | 3 | ns: hello-world 4 | 5 | defn hello(): 6 | 'Hello, world!' 7 | -------------------------------------------------------------------------------- /ys/test/hello.ys: -------------------------------------------------------------------------------- 1 | --- !YS-v0 2 | say: "Hello" 3 | identity: 12345 4 | -------------------------------------------------------------------------------- /ys/test/init: -------------------------------------------------------------------------------- 1 | #! bash 2 | 3 | ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P) 4 | 5 | BASE=$ROOT/ys 6 | 7 | export PYTHONPATH=$ROOT/python/lib 8 | 9 | export BPAN_ROOT=$BASE/.bpan 10 | 11 | source "$BPAN_ROOT/test/init" 12 | 13 | YS_BIN_DIR=${YS_BIN_DIR:-$BASE/bin} 14 | 15 | [[ -e $YS_BIN_DIR/ys ]] || 16 | die "No ys program at '$YS_BIN_DIR/ys'" 17 | 18 | export PATH=$YS_BIN_DIR:$PATH 19 | -------------------------------------------------------------------------------- /ys/test/loader.ys: -------------------------------------------------------------------------------- 1 | !YS-v0: 2 | 3 | foo: This is a string 4 | bar:: load("loadme.ys") 5 | baz:: load("loadme.ys").foo.bar 6 | -------------------------------------------------------------------------------- /ys/test/loadme.ys: -------------------------------------------------------------------------------- 1 | foo: 2 | bar: 3 | - aaa: 1 4 | - bbb: 2 5 | -------------------------------------------------------------------------------- /ys/test/merge-key.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | test:: 6 | - name: Merge key simple 7 | data: | 8 | foo: bar 9 | <<: 10 | bar: baz 11 | want: | 12 | foo: bar 13 | bar: baz 14 | 15 | - name: Mapping key wins 16 | data: | 17 | foo: 1 18 | <<: 19 | foo: 2 20 | bar: 3 21 | 22 | want: | 23 | foo: 1 24 | bar: 3 25 | 26 | - name: Multiple << keys - last wins 27 | data: | 28 | foo: 1 29 | <<: 30 | bar: 2 31 | <<: 32 | bar: 3 33 | want: | 34 | foo: 1 35 | bar: 3 36 | 37 | - name: Sequence of maps in << merge key 38 | data: | 39 | foo: 1 40 | <<: [{bar: 2}, {baz: 3}] 41 | want: | 42 | foo: 1 43 | bar: 2 44 | baz: 3 45 | 46 | - name: Key order comes from main map 47 | data: | 48 | foo: 1 49 | baz: 3 50 | <<: [{bar: 2}, {quux: 4}] 51 | want: | 52 | foo: 1 53 | baz: 3 54 | bar: 2 55 | quux: 4 56 | 57 | - name: Chained << merges 58 | data: | 59 | one: &a 60 | a: 1 61 | two: &b 62 | <<: *a 63 | b: 2 64 | three: 65 | <<: *b 66 | c: 3 67 | want: | 68 | one: 69 | a: 1 70 | two: 71 | b: 2 72 | a: 1 73 | three: 74 | c: 3 75 | b: 2 76 | a: 1 77 | 78 | - name: https://github.com/yaml/yamlscript/issues/197#issuecomment-2514783585 79 | data: | 80 | one: &a 81 | a: 1 82 | two: &b 83 | <<: *a 84 | b: 2 85 | three: *b 86 | want: | 87 | one: 88 | a: 1 89 | two: 90 | b: 2 91 | a: 1 92 | three: 93 | b: 2 94 | a: 1 95 | 96 | done: 7 97 | -------------------------------------------------------------------------------- /ys/test/number.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | test:: 6 | - code: '1' 7 | want: 1 8 | - code: '0' 9 | want: 0 10 | - code: '000' 11 | want: 0 12 | - code: '-000' 13 | want: 0 14 | - code: '1.2' 15 | want: 1.2 16 | - code: '01.2' 17 | want: 1.2 18 | - code: 5:inc 19 | want: 6 20 | - code: 3.4.5 21 | what: error 22 | want: 'Invalid number: 3.4.5' 23 | - code: 5.inc() 24 | want: 6 25 | - code: 55.5.inc() 26 | want: 56.5 27 | - code: 55.5:inc 28 | want: 56.5 29 | - code: 3.4.5:inc 30 | what: error 31 | want: 'Invalid number: 3.4.5' 32 | - code: 3.4.5.inc() 33 | what: error 34 | want: 'Invalid number: 3.4.5' 35 | - code: 3/44+5.inc() 36 | what: error 37 | want: 'Invalid number: 3/44+5' 38 | - code: 35.inc 39 | what: error 40 | want: 'Invalid number: 35.inc' 41 | - code: 35.inc + 10 42 | what: error 43 | want: 'Invalid number: 35.inc' 44 | - code: -1.inc() 45 | want: 0 46 | - code: -1.5.inc() 47 | want: -0.5 48 | - code: -1:inc 49 | want: 0 50 | - code: -1.5:inc 51 | want: -0.5 52 | - code: 5.in?(1 .. 10) 53 | want: true 54 | - code: 5.5.in?(1 .. 10) 55 | want: false 56 | 57 | done: 22 58 | -------------------------------------------------------------------------------- /ys/test/process.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | env-update:: 6 | FOO_BAR: BAZ 7 | 8 | test:: 9 | - code: | 10 | sh-out:: bash -c 'echo $FOO_BAR' 11 | want: BAZ 12 | 13 | - code: | 14 | sh-out {:dir '..'}:: bash -c 'echo $FOO_BAR' 15 | want: BAZ 16 | 17 | - code: | 18 | sh("bash -c 'echo \$FOO_BAR'").out:chomp 19 | want: BAZ 20 | 21 | - code: | 22 | sh({:dir '..'} 'bash -c "echo $FOO_BAR"').out:chomp 23 | want: BAZ 24 | 25 | done: 4 26 | -------------------------------------------------------------------------------- /ys/test/shebang1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | defn main(*): 4 | say: ARGV.0 5 | -------------------------------------------------------------------------------- /ys/test/show-args: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | defn main(*args): 4 | say: 5 | pr-str: ARGV 6 | pr-str: args 7 | -------------------------------------------------------------------------------- /ys/test/slice.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | hash =: -{ 6 | \'aaa 111 7 | 'bbb' 222 8 | :ccc 333 9 | 444 444 10 | 'nil' 555 11 | 'true' 666 12 | } 13 | 14 | keys1 =: q(aaa bbb ccc) 15 | 16 | test:: 17 | - code: hash.slice(444 555) 18 | want:: -[444 nil] 19 | - code: hash.slice(q(aaa bbb ccc)) 20 | want:: -[111 222 333] 21 | - code: hash.slice(q(aaa bbb ccc) 444 qw(nil true)) 22 | want:: -[111 222 333 444 555 666] 23 | - code: hash.slice(keys1) 24 | want:: -[111 222 333] 25 | 26 | done: 4 27 | -------------------------------------------------------------------------------- /ys/test/str.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | use ys::taptest: :all 4 | 5 | test:: 6 | - code: -"".split() 7 | want: [] 8 | 9 | done: 10 | -------------------------------------------------------------------------------- /ys/test/taptest-failures.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source test/init 4 | 5 | read -r -d '' expect <<... || true 6 | ok 1 - String fail 7 | not ok 2 - Number fail 8 | # Failed test 'Number fail' 9 | # got: 42 10 | # expected: 43 11 | ok 3 - Pass expecting false 12 | not ok 4 - Fail expecting false 13 | # Failed test 'Fail expecting false' 14 | # got: true 15 | # expected: false 16 | not ok 5 - Fail expecting nil 17 | # Failed test 'Fail expecting nil' 18 | # got: true 19 | # expected: nil 20 | not ok 6 - Fail expecting nil as string 21 | # Failed test 'Fail expecting nil as string' 22 | # got: true 23 | # expected: "nil" 24 | 1..6 25 | ... 26 | 27 | cmd='ys test/taptest-failures.ys' 28 | is "$($cmd)" "$expect" "$cmd" 29 | 30 | done-testing 31 | -------------------------------------------------------------------------------- /ys/test/taptest-failures.ys: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | require ys::taptest: :all 4 | 5 | # Run the tests: 6 | test:: 7 | - name: String fail 8 | code: say("Hello") 9 | what: out 10 | want: Hello 11 | 12 | - name: Number fail 13 | code: 6 * 7 14 | want: 43 15 | 16 | - name: Pass expecting false 17 | code: 1 == 2 18 | want: false 19 | 20 | - name: Fail expecting false 21 | code: 3 == 3 22 | want: false 23 | 24 | - name: Fail expecting nil 25 | code: 3 == 3 26 | want: null 27 | 28 | - name: Fail expecting nil as string 29 | code: 3 == 3 30 | want: nil 31 | 32 | done: 6 33 | -------------------------------------------------------------------------------- /ys/test/transform.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | require ys::taptest: :all 4 | 5 | say: CWD 6 | 7 | base =: 8 | if CWD =~ /\/yamlscript$/: 9 | then: "$CWD/ys" 10 | else: CWD 11 | 12 | test:: 13 | - name: Check that `case` works like `cond` 14 | code: | 15 | x =: 42 16 | case type(x): 17 | String : "S" 18 | Boolean : "B" 19 | else : "X" 20 | want: X 21 | 22 | done: 23 | -------------------------------------------------------------------------------- /ys/test/unit-tests.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | require ys::taptest: test done 4 | 5 | AV =: fs-abs("$DIR/../../sample/advent") 6 | 7 | hash =:: 8 | foo: one 9 | :bar: two 10 | 11 | test:: 12 | - name: 1.2.3 not a number 13 | code: 1.2.3 14 | what: error 15 | want: 'Invalid number: 1.2.3' 16 | 17 | - name: Function call 18 | code: 41 .inc() 19 | want: 42 20 | 21 | - name: Dot chain 22 | code: (1 .. 10).drop(2).take(3) 23 | want:: -[3 4 5] 24 | 25 | - name: Get nth 26 | code: (1 .. 10).5 27 | want: 6 28 | 29 | - name: Get string key maybe 30 | code: hash.foo 31 | want: one 32 | 33 | - name: Get string key single 34 | code: hash.'foo' 35 | want: one 36 | 37 | - name: Get string key double 38 | code: hash."foo" 39 | want: one 40 | 41 | - name: Get keyword key maybe 42 | code: hash.bar 43 | want: two 44 | 45 | - name: Get keyword key explicit 46 | code: hash.:bar 47 | want: two 48 | 49 | - code: '-[] |||: 1 && 0' 50 | want:: nil 51 | 52 | - code: '-"foo" *: 3' 53 | want: foofoofoo 54 | 55 | - code: -[123].#.? 56 | want: 1 57 | - code: -{}.#.! 58 | - code: a(0).?? 59 | 60 | - code: (1 .. 10):len.-- 61 | want: 9 62 | 63 | - code: a('world'):uc1 64 | want: World 65 | 66 | done: 67 | -------------------------------------------------------------------------------- /ys/test/yamlscript/test.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright 2023-2025 Ingy dot Net 2 | ;; This code is licensed under MIT license (See License for details) 3 | 4 | (ns yamlscript.test 5 | (:require 6 | [clojure.test :as test] 7 | [clojure.string :as str])) 8 | 9 | (def test-opts 10 | (atom {:verbose (System/getenv "TEST_VERBOSE")})) 11 | 12 | (defn do-verbose [label want] 13 | (when (:verbose @test-opts) 14 | (let [label (if label 15 | label 16 | (let [label (str/replace want #"\n" "\\n") 17 | label (if (> (count label) 50) 18 | (str (subs label 0 50) "...") 19 | label)] 20 | (str "'" label "'")))] 21 | (println (str "* Testing: " label))))) 22 | 23 | (defn is [got want & [label]] 24 | (let [want (if (string? want) 25 | (str/replace want #"''" "\"") 26 | want)] 27 | (do-verbose label want) 28 | (test/is (= want got)))) 29 | 30 | (defn like [got want & [label]] 31 | (do-verbose label want) 32 | (test/is (re-find want got))) 33 | 34 | (defn has [got want & [label]] 35 | (do-verbose label want) 36 | (test/is (str/index-of got want))) 37 | 38 | (comment 39 | ) 40 | -------------------------------------------------------------------------------- /ys/test/ys.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ys-0 2 | 3 | require ys::taptest: :all 4 | 5 | yaml1 =: | 6 | !YS-v0 7 | --- 8 | foo: boom 9 | --- 10 | !data 11 | bar:: +++.$.foo 12 | baz: 123 13 | 14 | test:: 15 | - code: yaml1:lines:rest:text:eval:yaml/dump 16 | want: | 17 | bar: boom 18 | baz: 123 19 | 20 | - code: yaml1:ys/eval:yaml/dump 21 | want: | 22 | bar: boom 23 | baz: 123 24 | 25 | - code: yaml1:ys/eval-stream:yaml/dump 26 | want: | 27 | - foo: boom 28 | - bar: boom 29 | baz: 123 30 | 31 | done: 32 | --------------------------------------------------------------------------------