diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e657de --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +# Technique + +This is the Technique Procedure Language, a programming language for +describing procedures in a structured but human-readable form. You can +consider it a domain-specific language (DSL) for writing procedures and +checklists. + +This language design has evolved over a long period, 20+ years, starting with +on-paper procedures for systems operations tasks, and then going through +different iterations of program and approach. The current version is Technique +v1, written in Rust. + +The Technique language allows you to write instructions to be read and +followed other humans. As a result, Technique doesn't look much like +programming code, but it is nevertheless a formally defined specification for +writing procedures and clear rules for executing them and recording their +outcomes. + +## Usage + +The _technique_ program has three subcommands: + +- _check_ \ + Validate the syntax, structure, and types in a Technique document. + +- _format_ \ + Format the code in the given Technique document, embellished with ANSI + syntax highlighting if run in a terminal. + +- _render_ \ + Render the Technique document into a printable PDF. This use the Typst + typestting language and so requires the _typst_ compiler be installed and on + `PATH`. + +## Contents + +This repository contains the _technique_ binary, which is the compiler for +Technique v1, along with a code formatter, and machinery to render procedures +as PDFs. Syntax highlighting is available for Vim, the Zed Editor, Sublime +Text, and the Typst typesetter. There's a language server, and an extension +for Zed, with VS Code and NeoVim on the way. + +- Syntax checking, code formatter, renderer (this repository) \ + +- Formal specification \ + +- Zed Editor support \ + +- Tree Sitter grammar (for syntax highlighting) \ + +- Typst and Vim support \ + + +## Examples + +To give a sense of the flavour of the language, here are a small selection of +Technique source files rendered to PDFs using the _technique render_ command. + +### Systems and Operations + +One of the original use cases behind this work was wanting to document the +procedures used in systems administration and network operations. This example +shows a simple list of such tasks: + + + + + +### Recipes + +Preparing a meal during the holidays is also a list of tasks, but often more +than one person needs to do things concurrently: + + + + + + +### Instructions + +This from a set of instructions guiding staff of what to do when an incident +occurs: + + + + + +### Larger processes + +Finally, an example showing using Technique to describe a much larger +procedure, in this case the entire process of doing systems engineering on a +software project. This pushes the limits of what the language is for, but +nevertheless illustrates that Technqiue can be used for very large structures +as well as very detailed ones: + + + + + +Detailed examples can be found in the _examples/_ and _tests/_ directories. +Documents written in Technique have file extension _\*.tq_. diff --git a/examples/prototype/ChristmasTurkey.tq b/examples/prototype/ChristmasTurkey.tq new file mode 100644 index 0000000..dc922cf --- /dev/null +++ b/examples/prototype/ChristmasTurkey.tq @@ -0,0 +1,199 @@ +% technique v1 +! Proprietary; © 2002-2019 Andrew Cowie + +christmas_dinner : Context -> Dinner + +# Christmas Dinner + +Recipe for a classic Christmas dinner. It is probably worth noting that this +can be followed on most any high holiday. The only things you really need are +patience, guests, and a turkey. + + 1. Assemble ingredients ~ ingredients + 2. Prepare the meal (ingredients) ~ meal + 3. Serve dinner (meal) ~ dishes + 4. Clean up after (dishes) + +assemble_ingredients : () -> Ingredients + +# Shopping List + +Assembling all necessary ingredients from various sources. + + @chef + 1. Get turkey from butcher { ~ t } + 2. Get stuffing ingredients { ~ s } + 3. Get breadsauce ingredients { ~ b } + +turkey : () -> Ingredients + +# Turkey + +For some reason people seem to think that they need an enormous bird. Don't +worry even if you are expecting a large party; if you've got lots of relatives +you can just leave out a few plates of cheese and crackers and they'll be full +long before dinner is served. + + ^butcher + - Buy turkey + { + [ + "Turkey" = 4 ± 1 kg + "Bacon" = 2 pieces + ] + } + +stuffing : () -> Ingredients + +# Stuffing + +Stuffing a bird actually makes it take longer to cook, but doing so adds +aroma, flavour, and helps preserve moisture and keeps the turkey tender. + + ^store + - Get seasoning ingredients + { + [ + "Salt" = 1 teaspoon + "Pepper" = 1 teaspoon + ] + } + + ^grocer + - Get vegetables + { + [ + "Carrots" = 1 each + "Celery" = 0.5 stalk + ] + } + + ^bakery + - Get bread + { + [ + "Bread" = 2 slices + ] + } + +breadsauce : () -> Ingredients + +# Breadsauce + +This ancient recipe from Northern Yorkshire calls for ... + + ^bakery + - Get bread + { + [ + "Bread" = 4 slices + ] + } + + ^store + - Get spices and milk + { + [ + "Salt" = 1 teaspoon + "Pepper" = 1 teaspoon + "Cloves" = 4 teaspoons + "Milk" = 100 mL + ] + } + + ^grocer + - Get onion + { + [ + "Brown Onion" = 0.5 bulb + ] + } + +prepare_meal(i) : Ingredients -> Meal + +# Prepare Meal + +Coordinating the preparation of all meal components. + + @chef + 1. Roast the turkey { (i) ~ turkey } + 2. Roast potatoes { (i) ~ potatoes } + 3. Make breadsauce { (i) ~ sauce } + 4. Prepare vegetables { (i) ~ raw } + 5. Make gravy { (i) ~ gravy } + 6. Wait for cooking { timer(3 hr) ~ t1 } + 7. Cook vegetables { (raw) ~ (veggies, water) } + 8. Combine gravy with vegetable water { (gravy, water) ~ gravy } + 9. Check turkey temperature { (turkey) ~ temp } + { + [ + "Final Temperature" = temp + ] + } + +roast_turkey(i) : Ingredients -> Turkey + +# Roast Turkey + + @chef + 1. Set oven temperature { (180 °C) ~ temp } + 2. Place bacon strips onto bird + 3. Put bird into oven + 4. Set timer for roasting { timer(3 h) ~ t } + 5. Record temperature + { + [ + "Roast temperature" = temp + ] + } + + @assistant + - Set the table + +cook_vegetables(veg) : VegetablesPrepared -> VegetablesCooked, VegetableWater + +# Cook Vegetables + + @chef + 1. Boil water + 2. Dunk greens in water + +combine(g, w) : Gravy, VegetableWater -> Gravy + +# Pour the vegetable water into the gravy + + @chef + - Combine gravy and vegetable water + +serve_dinner(m) : Meal -> DirtyDishes + +# Serve dinner and enjoy + +cleanup_after(d) : DirtyDishes -> () + +# Cleanup + +No one likes cleaning up. As far as I can tell, the only real justification +for having children is to help with doing the dishes on festive occasions. +Certainly I always hated my Aunt at holidays for making me dry dishes with a +dish towel when they would perfectly well air dry by themselves. + + @* + 1. Turn off oven { (0 °C) } + 2. Put knives away { } + 3. Turn lights out { } + +oven(temp) : Temperature -> () + +# Set oven temperature + + @chef + - Set temperature to { "oven at { temp }" } + +knives_away : + +# Put knives away + + @* + 1. Place knives in safe place + 2. Start dishwasher diff --git a/examples/prototype/DontPanic.tq b/examples/prototype/DontPanic.tq new file mode 100644 index 0000000..e4f75b7 --- /dev/null +++ b/examples/prototype/DontPanic.tq @@ -0,0 +1,123 @@ +% technique v1 +! CC BY 4.0; © 2020 Athae Eredh Siniath, and Others + +emergency_procedure : Incident -> Calm + +# Instructions + +Don't Panic! + +In the event of an incident, clear thinking is key. Challenge yourself to form +more than one hypothesis, and generate multiple options. The first solution +you think of is rarely the best one. + +As you consider options available, think of our values. Never forget the needs +of our customers and the trust they have placed in us. + + 1. + 2. + 3. { repeat } + +ensure_safety : Available -> Ready + +# Safety First + +Ensure your physical environment is free from danger, take measures to +maximize digital security, and establish reliable connectivity. + + - Ensure physical and digital safety + - Establish connectivity + +communicate : Ready -> Leader + +# Communicate + +Escalate quickly. Do not assume your manager or your team lead is aware of +what is happening. + +Write down everything, with timestamps. + + - Tell colleagues you are taking charge + +incident_action_cycle(s) : Situation -> Done + +# ORDeAL + +You are the leader now. Act like it. + + @leader + 1. Observe { (s) ~ e } + 2. Reflect { (e) ~ os } + 3. Decide { (os) ~ d } + 4. Act { (d) ~ r } + 5. Learn { (e, r) } + +observe : Situation -> Context + +# Observe + +Ask these questions: "What is happening? What is not happening?" Rapidly begin +gathering information and sharing context. Information becomes intelligence +only when it influences the thinking of the leader. + + - Gather information and share context + +reflect : Context -> Options + +# Reflect + +Ask yourself: "What can I do to influence the situation?" Interpret the data +you have. Identify threats. Deduce opportunities, alternatives, options, and +courses of action. + + 1. Think! + 2. Courses of action? + +decide : Options -> Decision + +# Decide + +Determine your tasks, roles of key colleagues. Identify constraints, and +establish limits. Communicate your intent upwards. + + 1. Determine your tasks + 2. Communicate your intent upwards + +act(d) : Decision -> Context + +# Act + +Execute the decision. + + 1. Execute { d } + +learn : Context, Outcome -> Situation + +# Learn + +Relate the outcomes of the decision and action taken to the environment. Did +the system actually change? In the way you expected? Ask yourself and your +team, "If we knew then what we know now, what would we do differently?" + + 1. Consider outcome. Did action result in change? + 2. What is the situation now? ~ situation + +Now go back to step 1. + +journal(e) : Event -> JournalEntry + +# Journal + +Record everything, with timestamps. As soon as a second person joins you in +responding to the incident, start verbalizing your actions to them and get +them to act as journalist; if you hand over to them, you take the notes. + + - Record event as it happens ~ msg + @journalist + { + [ + "timestamp" = now() + "message" = msg + "context" = "Details about { e }" + ] + } diff --git a/examples/prototype/SurgicalSafetyChecklist.tq b/examples/prototype/SurgicalSafetyChecklist.tq new file mode 100644 index 0000000..047496b --- /dev/null +++ b/examples/prototype/SurgicalSafetyChecklist.tq @@ -0,0 +1,88 @@ +% technique v1 +! CC BY-NC-SA 3.0 IGO; © 2009 World Health Organization + +surgical_safety_checklist : + +# Surgical Safety Checklist + +The checklist is designed to be read out loud by a team member, with the +Surgeon, the Anaesthetist, and the Nurse all confirming that the step has been +completed. + +The checklist has three sections. Each section should take no longer than a +minute. + +I. Before induction of anaesthesia + +II. Before skin incision + +III. Before the patient leaves the operating room + +before_anesthesia : + +# Before induction of anaesthesia + + 1. Has the patient confirmed his/her identity, site, procedure, and + consent? + 'Yes' + 2. Is the site marked? + 'Yes' | 'Not Applicable' + 3. Is the anaesthesia machine and medication check complete? + 'Yes' + 4. Is the pulse oximeter on the patient and functioning? + 'Yes' + 5. Does the patient have a: + - Known allergy? + 'No' | 'Yes' + - Difficult airway or aspiration risk? + 'No' | 'Yes' and equipment/assistance available + - Risk of blood loss > 500 mL? + 'No' | 'Yes' and two IVs planned and fluids available + +before_incision : + +# Before skin incision + + 1. Confirm all team members have introduced themselves by name and role + 'Introduced' + 2. Confirm the patient's name, procedure, and where the incision will be + made. + 'Confirmed' + 3. Confirm antibiotic prophylaxis have been given within the last 60 + minutes. + 'Yes' | 'Not Applicable' + 5. Review anticipated critical events. + @surgeon + a. What are the critical or non-routine steps? + b. How long will the case take? + c. What is the blood loss expected? + @anaesthetist + d. Are there any patient-specific concerns? + @nursing_team + e. Has sterility (including indicator results) been confirmed? + f. Has the equipment issues been addressed? + 6. Is essential imaging displayed? + 'Yes' | 'Not Applicable' + +before_leaving : + +# Before patient leaves operating room + + 1. Verbally confirm: + - The name of the surgical procedure(s). + - Completion of instrument, sponge, and needle counts. + - Specimen labelling + { foreach specimen in specimens } + @nursing_team + a. Read specimen labels aloud, including patient name. + - Whether there are any equipment problems to be addressed. + 2. Post-operative care: + @surgeon + a. What are the key concerns for recovery and management of this + patient? + @anesthetist + b. What are the key concerns for recovery and management of this + patient? + @nursing_team + c. What are the key concerns for recovery and management of this + patient? diff --git a/examples/prototype/SystemsEngineeringProcess.tq b/examples/prototype/SystemsEngineeringProcess.tq new file mode 100644 index 0000000..724d43e --- /dev/null +++ b/examples/prototype/SystemsEngineeringProcess.tq @@ -0,0 +1,133 @@ +% technique v1 +! MIT; © 2018 Roy Kalawsky and Andrew Cowie + +systems_engineering_process : + +I. Define Goals and Objectives + +establish_product_concept : () -> Concept + + 1. Establish Product Concept + +II. Requirements Definition and Architecture + +requirements_and_architecture : Concept -> Requirements, Architecture + + 2. Define Requirements (concept) + 3. Determine Architecture (concept) + +define_requirements : Concept -> Requirements + +determine_architecture : Concept -> Architecture + +III. Implementation + +design_and_build : Requirements -> System + +# Engineering Design, Build, and Verification + + 4. Engineering Design (requirements) ~ designs + 5. Software Development + { foreach design in designs } + a. (design) ~ component + 6. Integration Testing + { foreach (design, component) in zip(designs, components) } + a. (design, component) + +engineering_design : Requirements -> [Design] + +# Engineering Design + +Given a set of requirements the engineering profession can undertake detailed +analysis and turn the _idea_ into a technical _design_ for how the problem +will be approached and what is actually to be built. + +implement : Design -> Component + +# Build and Test + + 1. Prototypes and explorations (design) + 2. Software Development + 3. Local Testing and Experimentation + +build_software : Design -> Component + +# Software Development + + 1. Define Interfaces and Types + @programmers + a. ~ types + 2. Write Program code + @programmers + a. (design, types) ~ component + 3. Unit Testing + @programmers + a. (component) + +define_interfaces : Design -> Interfaces + +writing_code : Design, Interfaces -> Component + +unit_tests : Component -> Component + +local_experiments : Component -> Component + +# Local Testing and Experimentation + + 7. Local Testing + +integration_testing : Design, Component -> SubSystem + +# System Verification + + 8. Integration Testing + +IV. System Validation + +functional_testing : [SubSystem] -> System + + 9. Functional Testing + +validate_system : Requirements, System -> Product + + 10. Agree requirements have been met + @leadership + - (requirements, system) ~ product + 11. Product Launch + @marketing + @sales + - (product) + +acceptance_decision : Requirements, System -> Product + +product_release : Product -> Product + +V. Production + +operations : Product -> Product + + 12. Ongoing Operations + @operators + @users + @management + +changes_upgrades : Product, ChangeRequest -> Product + + 13. Changes and Upgrades + @management + a. Identify new requirements + @engineering + b. Assess impact on system architecture + c. Create a design for the both + - the change, and + - the resultant changed component + d. Implement the change + e. Test the updated component + f. Re-integrate System + @management + g. Validate its functionality ~ product2 + @leadership + h. Release the updated system (product2) + +VI. Retirement or Replacement + +decommissioning : System -> () + + 14. Decommission System diff --git a/examples/screenshots/ChristmasTurkey.png b/examples/screenshots/ChristmasTurkey.png new file mode 100644 index 0000000..05f3cd6 Binary files /dev/null and b/examples/screenshots/ChristmasTurkey.png differ diff --git a/examples/screenshots/DontPanic.png b/examples/screenshots/DontPanic.png new file mode 100644 index 0000000..e2ca974 Binary files /dev/null and b/examples/screenshots/DontPanic.png differ diff --git a/examples/screenshots/LocalNetwork.png b/examples/screenshots/LocalNetwork.png new file mode 100644 index 0000000..3a25d07 Binary files /dev/null and b/examples/screenshots/LocalNetwork.png differ diff --git a/examples/screenshots/SystemsEngineeringProcess.png b/examples/screenshots/SystemsEngineeringProcess.png new file mode 100644 index 0000000..f82bcf3 Binary files /dev/null and b/examples/screenshots/SystemsEngineeringProcess.png differ diff --git a/tests/formatting/golden.rs b/tests/formatting/golden.rs index c7da535..ad7a48b 100644 --- a/tests/formatting/golden.rs +++ b/tests/formatting/golden.rs @@ -55,11 +55,7 @@ fn show_diff(original: &str, formatted: &str, file_path: &Path) { } } -#[test] -fn ensure_identical_output() { - // Read all .tq files from examples/prototype/ - let dir = Path::new("tests/golden/"); - +fn check_directory(dir: &Path) { // Ensure the directory exists assert!(dir.exists(), "examples directory missing"); @@ -121,3 +117,9 @@ fn ensure_identical_output() { panic!("All examples must format unchanged"); } } + +#[test] +fn ensure_identical_output() { + check_directory(Path::new("tests/golden/")); + check_directory(Path::new("examples/prototype/")); +} diff --git a/tests/samples/LocalNetwork.tq b/tests/samples/LocalNetwork.tq new file mode 100644 index 0000000..354dc8f --- /dev/null +++ b/tests/samples/LocalNetwork.tq @@ -0,0 +1,15 @@ +local_network : + +# Local Network Connectivity + +Establish that the local network environment is functioning. + + 1. Check physical network interface { exec( + ```bash + ip addr + ``` + ) } and look for eth0 being marked UP. + 2. Check local network connectivity + 3. Check local DHCP is working + 4. Check local DNS responding + 5. Verify reachability of local network gateway