{"id":13410753,"url":"https://github.com/wkhere/bcl","last_synced_at":"2025-04-09T09:33:06.496Z","repository":{"id":194544928,"uuid":"688560239","full_name":"wkhere/bcl","owner":"wkhere","description":"Basic Configuration Language","archived":false,"fork":false,"pushed_at":"2025-03-19T18:53:07.000Z","size":331,"stargazers_count":25,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T00:32:44.271Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wkhere.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-07T15:47:06.000Z","updated_at":"2025-03-25T13:04:43.000Z","dependencies_parsed_at":"2024-04-04T00:32:22.893Z","dependency_job_id":"e773401a-19a4-49d9-95a7-c1b1767aa05d","html_url":"https://github.com/wkhere/bcl","commit_stats":null,"previous_names":["wkhere/bcl"],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wkhere%2Fbcl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wkhere%2Fbcl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wkhere%2Fbcl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wkhere%2Fbcl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wkhere","download_url":"https://codeload.github.com/wkhere/bcl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271484,"owners_count":20911586,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:01:08.914Z","updated_at":"2025-04-09T09:33:06.489Z","avatar_url":"https://github.com/wkhere.png","language":"Go","readme":"BCL\n===\n\n[![Build Status](https://github.com/wkhere/bcl/actions/workflows/go.yml/badge.svg)](https://github.com/wkhere/bcl/actions/workflows/go.yml)\n[![Coverage Status](https://coveralls.io/repos/github/wkhere/bcl/badge.svg?branch=master)](https://coveralls.io/github/wkhere/bcl?branch=master)\n[![Go Report Card](https://goreportcard.com/badge/github.com/wkhere/bcl)](https://goreportcard.com/report/github.com/wkhere/bcl)\n[![Go Reference](https://pkg.go.dev/badge/github.com/wkhere/bcl.svg)](https://pkg.go.dev/github.com/wkhere/bcl)\n\nBasic Configuration Language.\n\n__BCL__ is like HCL (the language driving Terraform, Packer and friends),\nbut more basic:\n\n* no dollar-referenced variables; variable name can be used in an expression\n  as it is\n* block starts with `def` keyword; seems to be more general\n  compared to Terraform's `resource` keyword\n* dead-simple API: variables get evaluated automatically and fill the fields of\n  the output structure;\n  no [strange limitations] of where variables can be defined\n* variables with lexical scope\n* nested definitions\n* one-pass lexer, parser and VM executor\n* deserialization aka unmarshalling to static Go structs (possibly nested)\n\nWhile being basic, BCL also has features reaching beyond HCL:\n\n* rich expressions operating on strings, int \u0026 float numbers, and booleans\n* planned: make the outside world accessible via environment variables, or via\n  running a command and catching its output\n\n### Example:\nBCL:\n```hcl\nvar domain = \"acme.com\"\nvar default_port    = 8400\nvar local_port_base = default_port + 1000\n\ndef tunnel \"myservice-prod\" {\n\thost = \"prod\" + \".\" + domain\n\tlocal_port  = local_port_base + 1\n\tremote_port = default_port\n\tenabled = true\n\n\tdef extras {\n\t\tmax_latency = 8.5 # [ms]\n\t}\n}\n\nbind tunnel -\u003e struct\n```\nGo:\n```Go\ntype Tunnel struct {\n\tName       string\n\tHost       string\n\tLocalPort  int\n\tRemotePort int\n\tEnabled    bool\n\tExtras     struct {\n\t\tMaxLatency float64\n\t}\n}\nvar config Tunnel\n\nerr := bcl.UnmarshalFile(file, \u0026config)\nfmt.Println(strings.ReplaceAll(fmt.Sprintf(\"%+v\", config), \" \", \"\\n  \"))\n```\nOutput:\n```\n{Name:myservice-prod\n  Host:prod.acme.com\n  LocalPort:9401\n  RemotePort:8400\n  Enabled:true\n  Extras:{MaxLatency:8.5}}\n```\n### Syntax\n\nBCL has statements and expressions.\n\nA basic statement is `def block_type [block_name] {...}` to define a block with\n`field = value` expressions inside.\nSuch block after running [Interpret] will be available as \na [Block] with a map of fields,\nand can be put into a static Go struct via [Bind] or [Unmarshal].\nBlocks can be nested.\n\nBoth toplevel scope and a block can have variables created with \nthe `var x = expr` statement, or just `var x` which leaves it uninitialized.\nVariables do not count when produding result Block structures, but they are\ntaking part of the state flow.\n\nVariables have lexical scope. Any block has access to the varables declared\nat the toplevel and also nested block have access to their parent's variables.\nThere are no forward declarations.\n\nVariables are mutable and can be mutated with the `eval x = expr` statement.\nThis statement solely exists to allow evaluation of expressions in the context\nexpecting stamenents, that is at the toplevel. Please note that inside the block\nthe raw statements are allowed, for example `field = value` is actually\nan assignment expression. So, when in block, it's good to remember whether \nwe are operating on fields or variables. This may be made more explicit in the future.\n\nThe last stament in the clan is `print expr` which is useful for debugging.\n\nMore on expressions below.\n\n### Expressions, data conversions\n\nThere are three basic types: numbers (int and float), strings and booleans.\n\nValues in expressions know their types, although they are not enforced\nin the language; certain operations can cause runtime error.\n\nNumber arithmetics use int or float operations depending on the values\ninvolved; if any of the operands is float, then the int part is transparently\nconverted to float. Complex numbers are not supported atm.\n\nStrings can be concatenated with the plus `+`. \nIf the right side of such plus is a number, it will be transparently\ncoverted to string. However, the number plus string is an error.\n\nAnother string operator borrowed from numbers is asterisk `*`, this time\nthe left side must be a string and right side just an int; the result is\nrepeating the string given times.\n\nEquality comparisons `==`, `!=` are allowed between all types, including mixing them.\nObviously values of different non-number types are not equal.\n\nOrder comparisons `\u003c`, `\u003e`, , `\u003c=`, `\u003e=` are allowed between numbers and between strings,\nbut not between mixed types.\n\nThere are boolean operators `and`, `or`, `not` behaving like in Python,\nor like `\u0026\u0026`, `||`, `!` in Ruby [1]:\nthey are short-cirtuit and retain the type of an operand \n(`1==1 and 42` will return 42). Non-boolean types can be a boolean operand;\nfor this, there is a definition what is considered \"falsey\": `false`, `nil`,\nempty string, and zero, like in Python.\n\nBoolean constants are `true` and `false`.\nAnother constant is `nil`, value of an uninitialized variable (`var a`).\n\n[1] Note that in Ruby `!` has surprising priority, though.\n\n\n### Note on the parser\n\nVersions up to v0.7.x used goyacc, since v0.8.0 there is a top-down Pratt parser\nwith bytecode VM.\n\n\n### Cool stuff\n\nInternals can be peeked in many ways, here is bytecode disassembly,\nexecution trace with stack content, plus some stats:\n```\n./bcl -dts \u003c\u003c\u003c'var x=1; def block{eval x=x+2; field=x}'\n== /dev/stdin ==\n0000    1:8  ONE\n0001   1:20  DEFBLOCK      0 'block'         1 ''\n0004   1:28  GETLOCAL      0\n0006   1:30  CONST         2 '2'\n0008      |  ADD\n0009      |  SETLOCAL      0\n0011      |  POP\n0012   1:39  GETLOCAL      0\n0014      |  SETFIELD      3 'field'\n0016      |  POP\n0017   1:40  ENDBLOCK\n0018    2:1  POP\n0019      |  RET\npstats.tokens:        20\npstats.localMax:       1\npstats.depthMax:       1\npstats.constants:      4\npstats.opsCreated:    13\npstats.codeBytes:     20\n             0: \n0000    1:8  ONE\n             1: [ 1 ]\n0001   1:20  DEFBLOCK      0 'block'         1 ''\n             1: [ 1 ]\n0004   1:28  GETLOCAL      0\n             2: [ 1 ][ 1 ]\n0006   1:30  CONST         2 '2'\n             3: [ 1 ][ 1 ][ 2 ]\n0008      |  ADD\n             2: [ 1 ][ 3 ]\n0009      |  SETLOCAL      0\n             2: [ 3 ][ 3 ]\n0011      |  POP\n             1: [ 3 ]\n0012   1:39  GETLOCAL      0\n             2: [ 3 ][ 3 ]\n0014      |  SETFIELD      3 'field'\n             2: [ 3 ][ 3 ]\n0016      |  POP\n             1: [ 3 ]\n0017   1:40  ENDBLOCK\n             1: [ 3 ]\n0018    2:1  POP\n             0: \n0019      |  RET\nxstats.tosMax:         3\nxstats.blockTosMax:    1\nxstats.opsRead:       13\nxstats.pcFinal:       20\n```\n\n\n[strange limitations]: https://stackoverflow.com/a/73745980/229154\n[Block]: https://pkg.go.dev/github.com/wkhere/bcl#Block\n[Interpret]:  https://pkg.go.dev/github.com/wkhere/bcl#Interpret\n[Bind]:       https://pkg.go.dev/github.com/wkhere/bcl#Bind\n[Unmarshal]:  https://pkg.go.dev/github.com/wkhere/bcl#Unmarshal\n","funding_links":[],"categories":["Configuration","配置"],"sub_categories":["Standard CLI","标准CLI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwkhere%2Fbcl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwkhere%2Fbcl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwkhere%2Fbcl/lists"}