{"id":18260016,"url":"https://github.com/hungrybluedev/typestate_v","last_synced_at":"2026-03-19T03:34:23.174Z","repository":{"id":182349620,"uuid":"663887466","full_name":"hungrybluedev/typestate_v","owner":"hungrybluedev","description":null,"archived":false,"fork":false,"pushed_at":"2023-08-28T19:08:26.000Z","size":979,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-14T18:36:26.396Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"V","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hungrybluedev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-07-08T11:04:48.000Z","updated_at":"2023-10-07T18:59:19.000Z","dependencies_parsed_at":"2024-11-05T11:03:35.943Z","dependency_job_id":null,"html_url":"https://github.com/hungrybluedev/typestate_v","commit_stats":null,"previous_names":["hungrybluedev/typestate_v"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hungrybluedev%2Ftypestate_v","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hungrybluedev%2Ftypestate_v/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hungrybluedev%2Ftypestate_v/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hungrybluedev%2Ftypestate_v/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hungrybluedev","download_url":"https://codeload.github.com/hungrybluedev/typestate_v/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247947825,"owners_count":21023058,"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-11-05T10:41:33.834Z","updated_at":"2026-02-03T02:36:04.913Z","avatar_url":"https://github.com/hungrybluedev.png","language":"V","funding_links":[],"categories":[],"sub_categories":[],"readme":"# typestate-v\n\n## Description\n\nProof of concept for a typestate checker for V. This is built as a part of my MSc thesis at the University of Glasgow.\n\nLong term goal is to merge this into the V compiler itself as an additional stage before `cgen`.\n\n### What is typestate?\n\nThere are instances where we want to enforce a certain order of operations on a type. For example, we want to ensure that a file is opened before it is read from. We can definitely do this with a runtime check, but it would be better if we could do this at compile time.\n\nWe describe the order of operations on a type using an ordered list of _states_ that a type can be in. Then the relationship between these states is described in a _protocol_ that essentially contains information needed to build a finite state machine.\n\nWe then traverse the [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) during compilation and check that the operations on a type are in the correct order. Therefore, we obtain the etymology of the name _typestate_; attaching states to types and using a state-machine to check the validity of the protocol.\n\n## Pre-requisites\n\n### Install V from source.\n\nIt is recommended to follow the instructions from\nthe [official documentation](https://github.com/vlang/v/blob/master/README.md#installing-v-from-source).\n\nIf you're on a Unix-like system, you can run the following commands to install V from source:\n\n```bash\ncd some/appropriate/path\ngit clone --depth=1 https://github.com/vlang/v\ncd v\nmake\n```\n\nIf on Windows, please refer to the additional instructions in the official documentation.\n\n### Symlink the `v` binary.\n\nEnsure that the `v` binary is in your `PATH` by symlinking it:\n\n```bash\nsudo ./v symlink\n```\n\nThe process is similar on Windows. Refer to the official documentation for more details.\n\nTest that the installation was successful by running:\n\n```bash\nv version\n```\n\n### Updating V\n\nOnce V is installed, you can update it by running:\n\n```bash\nv up\n```\n\n## Usage\n\nClone this repository:\n\n```bash\ncd some/appropriate/path\ngit clone ...\ncd typestate_v\n```\n\nRun the main binary with:\n\n```bash\nv run . [path/to/case/study]\n```\n\nIf you want to view the help information, run:\n\n```bash\nv run . help\n```\n\nTo run the typestate checker on all enabled case studies, run:\n\n```bash\nv run . case-study\n```\n\nTo generate a graph of the finite state machine for a case study, run:\n\n```bash\nv run . viz [path/to/case/study]\n```\n\nIt will output the DOT representation of the graph to the terminal. If you have `graphviz` installed, a PNG image will be generated in the same directory as the case study.\n\n## Case Studies\n\n### Directory Structure\n\nThe case studies are located in the `src/case_studies` directory. Each case study is contained in its own directory. There are sub-directories for each case study indicating different inputs and expected errors (if any).\n\n### Running a Case Study\n\nSimply run:\n\n```bash\nv run [path/to/case/study]\n```\n\nNotice the lack of a `.` before the path. This is because we are running the case-study, not the main typestate checker.\n\n## Protocol Syntax\n\nA valid protocol is an instance of the `tpstv.Protocol` type. It is defined as follows:\n\n```v\npub struct Protocol[T, S] {\n\tname        string    [required]\n\tdescription string\n\trules       []Rule[S] [required]\n}\n\npub struct Rule[S] {\n\tname        string [required]\n\tdescription string\n\tstart       S      [required]\n\tend         S      [required]\n\tstimulus    string [required]\n}\n```\n\nThe `T` type parameter is the type that the protocol is defined for. The `S` type parameter is the type of the states in the protocol which is defined using an enumeration (aka _enum_). The `name` field is the name of the protocol. The `description` field is a description of the protocol. The `rules` field is a list of rules that define the protocol.\n\nA rule is defined by a `name`, `description`, `start`, `end` and `stimulus`. The `name` field is the name of the rule. The `description` field is a description of the rule. The `start` field is the starting state of the rule. The `end` field is the ending state of the rule. Both of these must be valid enum values defined in the associated typestate enum.\n\nThe `stimulus` field is the stimulus that causes the transition from the starting state to the ending state. This is defined using a string and is in the format `Type.method`. In case of static methods, the format is `Type.static.method`. The `Type` must be the same as the type that the protocol is defined for.\n\nA few more validation rules are applied to ensure that we can build a valid discrete finite state machine from the protocol.\n\nCheck the `src/case_studies` directory for examples of protocols. Here are some of the valid protocols in graphical form:\n\n![Read-only file protocol](src/case_studies/01_read_only_file/case03_normal/fsm.png)\n\n![Speaker protocol](src/case_studies/02_speaker/case03_normal/fsm.png)\n\n![Histogram protocol](src/case_studies/03_histogram/case03_normal/fsm.png)\n\n![Email API protocol](src/case_studies/04_email_api/case03_normal/fsm.png)\n\n![Fibonacci protocol](src/case_studies/05_fibonacci/case03_normal/fsm.png)\n\n## Adding a Case Study\n\n1. Create a new directory in `src/case_studies` with the name of the case study.\n2. Create a `[name].v` file in a sub-directory called `case03_normal`.\n3. Create a `protocol.v` file in the same directory.\n4. Write a valid stand-alone V program in the `[name].v` file.\n5. Make sure that the `protocol.v` file contains an enum of the states that the target type can be in.\n6. Define a constant `protocol` of the type `tpstv.Protocol` in the `protocol.v` file.\n7. Make sure the typestate checker passes on the case study.\n8. Add more variants based on the other examples.\n\nCurrently, only one protocol is supported per project but it can be modified to support multiple protocols.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhungrybluedev%2Ftypestate_v","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhungrybluedev%2Ftypestate_v","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhungrybluedev%2Ftypestate_v/lists"}