{"id":13610202,"url":"https://github.com/holgerl/hilvl","last_synced_at":"2025-04-12T22:33:09.897Z","repository":{"id":35550858,"uuid":"39822478","full_name":"holgerl/hilvl","owner":"holgerl","description":"The hilvl programming language","archived":false,"fork":false,"pushed_at":"2021-10-06T07:02:22.000Z","size":212,"stargazers_count":7,"open_issues_count":9,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-01T19:54:30.670Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/holgerl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-28T08:35:50.000Z","updated_at":"2024-07-19T23:03:36.000Z","dependencies_parsed_at":"2022-09-17T20:22:28.300Z","dependency_job_id":null,"html_url":"https://github.com/holgerl/hilvl","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holgerl%2Fhilvl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holgerl%2Fhilvl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holgerl%2Fhilvl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holgerl%2Fhilvl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/holgerl","download_url":"https://codeload.github.com/holgerl/hilvl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223549141,"owners_count":17163603,"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-08-01T19:01:42.398Z","updated_at":"2024-11-07T16:30:50.965Z","avatar_url":"https://github.com/holgerl.png","language":"JavaScript","readme":"# The hilvl programming language\n\nHilvl is a programming language that is versatile but with a very small syntax. All code in hilvl are **single-argument** invocations of **actions** that belong to **services**.\n\nServices are the fundamental building blocks of a hilvl program. And the name hilvl reflects how this is a higher level of abstraction than objects and functions.\n\n[Try it online (REPL)](http://holgerl.github.io/hilvl/)\n\n### Example of hilvl\n\n*(If you don't get this, skip to [the chapters below](https://github.com/holgerl/hilvl#structure-of-the-hilvl-language).)*\n\n\u003c!-- test-example1.hl --\u003e\n```javascript\n@ var foo = 42\n@ var bar = (2 + 40)\n\t\n@ . foo == (@ . bar) then\n\t@ set foo = 0\n\t\n@ var myList = \n\t1\n\t2\n\t3\n\t\n@ . myList loop\n\t@ set foo = (@ . foo + (@ . element))\n\n@ var myMap =\n\tMap of\n\t\t\"firstname\" , \"Ola\"\n\t\t\"lastname\" , \"Nordmann\"\n\n@ var MyService := \n\t@ var myAction :\n\t\t@ . argument + 10\n\t\t\nMyService myAction (@ . foo) // foo is now 6, and this returns 16\n```\n\t\n## Structure of the hilvl language\n\n### Service, action and argument\n\nAll statements in hilvl are invocations of single argument actions that are part of some service:\n\n```javascript\nService action argument\n```\n\nFor instance:\n\n```javascript\nTextUtil makeUppercase \"hello\"\nScoreKeeper add 10\n```\n\nThe magic happens when an action returns another service that can be called in a chain:\n\n```javascript\nSandwichMaker makeNewSandwich \"cheese\" addSome \"tomato\"\n```\n\n\u003cimg src=\"https://github.com/holgerl/hilvl/raw/master/notes/hilvl-example-1.png\" alt=\"hilvl syntax tree\" width=\"600\"\u003e\n\nServices can of course be arguments to other actions:\n\n```javascript\nChooser makeChoice (StrategyMaker mustBeLargerThan 10)\n```\n\n\u003cimg src=\"https://github.com/holgerl/hilvl/raw/master/notes/hilvl-example-2.png\" alt=\"hilvl syntax tree\" width=\"600\"\u003e\n\n### It is all services\n\nEverything is a service in hilvl, even strings and numbers. And action names can be anything. This means that even this is an ordinary action invocation:\n\n```javascript\n2 + 40\n```\n\nHere, `2` is the service, `+` is the action and `40` is the argument. This action returns a new service `42`\n\nThere are only 8 reserved symbols in hilvl:\n\n`\"` `(` `)` `//` `true` `false` `(numbers)` `(whitespace)`\n\nThe rest are services and actions defined by either the user or the system. This means that all other characters can be used when defining an API. (Allthough, you probably don't want to use the same name as a system service.) \n\nHere is an example that uses unusal action and service names:\n\n```javascript\n@ set myVariableName = 42\n```\n\nHere, `@` is the service, `set` is the action and `myVariableName` is the argument. This returns a new service which has an action `=` that is called with `42` as an argument. `@` is actually a system service for handling scope. There is more about that later.\n\n#### Creating a service\n\nSince everything is a service, it is easy to make your own. The last statement of an action is its return value:\n\n\u003c!-- test-example7.hl --\u003e\n```javascript\n// Creating a new service with an action:\n@ var MyService := \n\t@ var myAction :\n\t\t@ var myVariable = (42 + (@ . argument))\n\t\t@.myVariable // This is the return value\n\t\t\nMyService myAction 1 // Using the service\n\n//result: 43\n```\n\n#### Importance of parantheses\n\nThere is no precedence in hilvl. This means that parantheses may be necessary to group arguments correctly:\n\n```javascript\n@ set myVar = 2 + 40     // This fails during runtime!\n```\n\nThis is wrong because the action named `=` will take `2` as its argument, but the resulting service will not have an action named `+`. The correct way is to group `2 + 40` to a single argument for the `=` action:\n\n```javascript\n@ set myVar = (2 + 40)    // This is correct\n```\n\n#### Intendation and lists\n\nEvery action takes only 1 argument, but that argument can be a list. Whitespace intendation is used to declare a list:\n\n```javascript\nMyUtil sort\n\t4\n\t2\n\t9\n\t3\n```\n\t\nHere, the argument is the list `[4,2,9,3]`.\n\nWhy use whitespace for this you ask? The point is that if you make a list of *statements*, then you have a block of code. All code in hilvl are lists of statements that can be passed around and invoked by other code.\n\nHere is an example:\n\n```javascript\nKeyboardService onEvent\n\tPlayer move \"up\"\n\tTime increase 1\n\tCollisionControl doCheck _\n```\n\nHere, the implementation of `onEvent` may decide itself when to evaluate the statements in the argument.\n\n##### Empty lists\n\nIf the argument is ommitted entirely, it is interpreted as an empty list:\n\n```javascript\n// This is an empty list:\n@ var emptyList =\n\n// The same applies inside parantheses:\n(MyService getValue) doSomething 42\n```\n\n### Syntactic sugar\n\nTo make the code more readable, a very simple shortcut is supported in the syntax:\n\n`foo.bar` is the same as `foo. bar` is the same as `foo . bar`\n\n`foo,bar` is the same as `foo, bar` is the same as `foo , bar`\n\nThis means that the `.` and `,` are action names even though there are no space around them. This is only for these actions. All other services, actions and arguments must have spaces between them. This is because they can be called anything except the reserved symbols, and this in turn is why hilvl is very versatile and can used for implementing domain specific languages.\n\nSyntactic sugar is considered to be evil, so this is the only sugar in hilvl.\n\n## Services and actions provided out-of-the-box\n\nThe hilvl runtime provides several useful services in addition to the scope service. These are called system services because their functionality can not be made in hilvl by itself. Hilvl also comes with a standard library implemented in the language itself, providing some useful services.\n\n### String\n\n```javascript\n\"foo\" + \"bar\" == \"foobar\"\n\"Hello!\" length _ == 6\n\"Hello!\" at 1 substringTo 4 == \"ell\"\n\"Hello !\" at 6 insert \"World\" == \"Hello World!\"\n\"foo\" == \"bar\" == false\n```\n\n### Number\n\n```javascript\n1 + 2 - 3 == 0\n10 \u003e 4 == true == (4 \u003c 10)\n123 as string == \"123\"\n\n@ var n = 0\n10 until\n\t// This will loop until n is 10\n\t@ set n = (@.n + 1)\n\t@.n\n```\n\n### Boolean\n\n```javascript\n1 \u003c 2 == true\nfalse != true\n\n@.n \u003c 10 then\n\t// This will run if n is lower than 10\n\tMyService myAction \n```\n\n### List\n\n```javascript\n@ var myList = \n\t40\n\t41\n\t42\n@.myList get 1 == 41\n\n@ var emptyList = \n\t\n@.myList loop\n\t// This will loop through every element in myList\n\t@.emptyList push (@.element) \n```\n\n##### The `,` action\n\nThere is a convenient action `,` on strings, numbers and booleans. It returns a list containing the value and the argument:\n\n```javascript\n1, 2 // This is the list [1,2]\n\"one\", \"two\" // This is the list [\"one\",\"two\"]\ntrue, false // This is the list [true,false]\n```\n\nA clever trick is that the List service also has a `,` action that returns a new list with the argument added. So it is possible to chain this with several elements:\n\n```javascript\n@ var myList = (\"foo\", \"bar\", \"baz\", \"hello\")\n```\n\n### Map\n\nThis is a simple key-value map.\n\n```javascript\n@ var myPlayer = \n\tMap of  \n\t\t\"name\", \"Holger\"\n\t\t\"score\", 120\n\t\t\"alive\", true\n\nmyPlayer put (\"score\", 121)\nmyPlayer get \"name\"\n\n@ var emptyMap = (Map of)\n```\n\n### IO \n\nThe `IO` service handles input and output to and from systems outside the hilvl runtime environment.\n\n```javascript\nIO print \"This will be printed in the console\"\n\n@ var fileContents = (IO readFile \"myfolder/myfile.txt\")\n```\n\n### Variables, scope and evaluation\n\nThe `Service action argument` structure and indentation based lists are combined with the scope system for great flexibility for the programmer.\n\nVariables are created, changed and read by using the scope service `@`:\n\n\u003c!-- test-example4.hl --\u003e\n```javascript\n@ var myVar // variable \"myVar\" is declared\n@ set myVar = 42 // myVar is given a value\n@ var myOtherVar = 10 // the variable service also has an = action for more consise code\n@.myVar + (@.myOtherVar) // the values of myVar and myOtherVar are read and added together\n\n//result: 52\n```\n\nAll variables are saved in the same scope. But to add a new nested scope, there is an action named `:=` on the variable service:\n\n\u003c!-- test-example5.hl --\u003e\n```javascript\n@ var myVar1 = 1\n@ var myVar2 = 2\n\n@ var myScope := // the two statements in the argument are now evaluated in a new scope:\n\t@ var myVar1 = 10\n\t@ set myVar2 = 20\n\t\n// we place the variables in a list that is returned as the result:\n@ var myList =\n\t@.myVar1\n\t@.myVar2\n\n//result: [1, 20]\n```\n\nNotice how `myVar1` kept its value because the change to `10` was done on a new variable with the same name in the inner scope. `myVar2` on the other hand, was not redeclared in the inner scope, and its value was thus changed to `20`. \n\nThe scopes are nested, which means that if a variable is used, its value will be searched for upwards in all parent scopes.\n\nAfter adding a new scope, the `:=` action acts exactly like the `=` action, and evalates the argument list. This means that any statements in the argument gets executed. And in the example above, this meant that the variables where changed.\n\nBut it is possible to set a value to a variable *without* evaluating the arguments. This is useful when we want to execute a block of code at a later time, or many times over. This is also the key mechanism for structuring code as services and actions. \n\nIt is done with the action `:`:\n\n\u003c!-- test-example6.hl --\u003e\n```javascript\n@ var bar = 1\n\t\n@ var foo : // the statement in the argument is not evaluated yet\n\t@ set bar = 2\n\t\n@ var barBefore = (@.bar)\n\t\n@ foo // this invokes the foo action with an empty argument, and the code is evaluated\n\n@ var barAfter = (@.bar)\n\n@ var results =\n\t@.barBefore\n\t@.barAfter\n\n//result: [1, 2]\n```\n\nIf a list of statements is executed, the value of the *last* statement is returned from the action. All hilvl code are lists of statements, so this is why the last value is always the result in the examples. \n\n## Advanced examples of hilvl\n\n#### Services as records\n\n```javascript\n@ var User1 := \n    @ var age : 34\n    @ var name : \"Bob\"\n\n@ var User2 := \n    @ var age : 36\n    @ var name : \"Alice\"\n\n@ var users =\n    @.User1\n    @.User2\n\n@.users loop\n    IO print (@.element name _ + \" \" + (@.element age _ as string))\n\t\n// Prints:\n// \"Bob 34\"\n// \"Alice 36\"\n```\n\n#### Recursion\n\n\u003c!-- test-recursive3.hl --\u003e\n```javascript\n@ var fibonacci :\n\t@ var scope : // A new scope is needed. Or else, the result variable is shared between the recursive calls\n\t\t@ var result = (@.argument)\n\t\t@.argument \u003e 1 then\n\t\t\t@ set result = \n\t\t\t\t@ fibonacci (@.result - 1) + (@ fibonacci (@.result - 2))\n\t\t@.result\n\t@ scope (@.argument)\n\t\n@ fibonacci 7\n\n//result: 13\n```\n\n#### Scope and higher-order programming\n\n\u003c!-- test-example2.hl --\u003e\n```javascript\n@ var foo = 10 // Variable in outer scope\n\n@ var MyService := \n\t@ var myAction :\n\t\t@ set foo = 42 // Variable in inner scope\n\t\t@ var myFunction : (@.argument) // Saving argument without evaluating it\n\t\t@ myFunction // Invoking the argument as an action\n\t\t\n@ var bar = \n\tMyService myAction (@.foo + 2) // Argument is evaluated before action is invocated\n\tMyService myAction // Argument is evaluated on demand by the myAction implementation\n\t\t@.foo + 2\n\tMyService myAction \n\t\t@ set foo = 50 // The inner scope is active during on demand evaluation\n\t\t@.foo + 2\n\t\t\n/*result\n[12, 44, 52]\n*/\n```\n\n#### Fluent programming\n\n\u003c!-- test-example3.hl --\u003e\n```javascript\n@ var Please := \n\t@ var add :\n\t\t@ var arg1 = (@.argument)\n\t\t@.Please // Returning the service itself\n\t@ var and :\n\t\t@ var arg2 = (@.argument)\n\t\t@.Please // Returning the service itself\n\t@ var andThen :\n\t\t@.arg1 + (@.arg2) + (@.argument)\n\t\t\nPlease add 42 and 50 andThen 100\n\t\n//result: 192\n```\n\n### How to run hilvl\n\nTo run a file with hilvl code: `node src/hl.js myFile.hl`\n\t\nTo run all tests: `node tests/run-all-tests.js`\n\nTo run HiTTP web framework: `node src/HiTTP.js examples/todo-webapp/backend.hl`\n","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholgerl%2Fhilvl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fholgerl%2Fhilvl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholgerl%2Fhilvl/lists"}