From 8c9a4679fb46064136cc9274cce205aa2687dd6d Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 24 Mar 2025 16:27:43 -0400 Subject: [PATCH] Initial commit --- .gitignore | 3 + README.md | 8 ++ koans.tm | 173 ++++++++++++++++++++++++++++++++++ lesson-templates/lesson-01.tm | 5 + lesson-templates/lesson-02.tm | 22 +++++ 5 files changed, 211 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100755 koans.tm create mode 100644 lesson-templates/lesson-01.tm create mode 100644 lesson-templates/lesson-02.tm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac8433b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +editor.txt +/lessons +.build diff --git a/README.md b/README.md new file mode 100644 index 0000000..44df957 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Tomo Koans + +This is a program to help you learn the Tomo programming language by walking +you through some example programs. + +``` +tomo koans.tm +``` diff --git a/koans.tm b/koans.tm new file mode 100755 index 0000000..6cf5893 --- /dev/null +++ b/koans.tm @@ -0,0 +1,173 @@ +#!/bin/env tomo + +use colorful +use shell +use commands + +enum TestResult(Success(output:Text), Error(err:Text), WrongOutput(actual:Text, expected:Text)): + func print(result:TestResult): + when result is Success(s): + $Colorful" + @(b,u:Program Output:) + $s + ":print() + is Error(e): + $Colorful" + @(b,u:Program Errors:) + + $e + ":print() + is WrongOutput(actual, expected): + $Colorful" + @(b,u:Program Output:) + @(red:$actual) + @(b,u:Expected:) + @(green:$expected) + ":print() + + func is_success(result:TestResult -> Bool): + when result is Success: return yes + else: return no + +struct Lesson(file:Path, description:Text, expected_output=none:Text): + func get_result(l:Lesson -> TestResult): + result := $Shell"COLOR=1 tomo -O 0 $(l.file)":result() + if not result:succeeded(): + return Error(Text.from_bytes(result.stderr)!) + + output := Text.from_bytes(result.stdout)! + if expected := l.expected_output: + if output != l.expected_output: + return WrongOutput(output, expected) + + return Success(output) + +LESSONS := [ + Lesson((./lessons/lesson-01.tm), "Getting Started", "Hello world$\n"), + Lesson((./lessons/lesson-02.tm), "Working with Text"), +] + +func ask_continue(): + _ := ask("$\033[2mPress Enter to continue...$\033[m", bold=no) + +func clear_screen(): + say("$\x1b[2J$\x1b[H", newline=no) + +func summarize_tests(highlight=none:Path): + $Colorful" + + @(yellow,b,u:Lessons) + ":print() + + passing := 0 + failing := 0 + for i,lesson in LESSONS: + result := lesson:get_result() + if result:is_success(): + passing += 1 + $Colorful" + @(green,bold:$(Text(i):left_pad(2)): "$(lesson.description)" (passes)) + ":print() + else: + failing += 1 + if lesson.file == highlight or (highlight == none:Path and failing == 1): + $Colorful" + @(red:$(Text(i):left_pad(2)): "$(lesson.description)" (not yet passing)) + ":print() + else: + $Colorful" + @(dim:$(Text(i):left_pad(2)): "$(lesson.description)" (not yet passing)) + ":print() + + completed := (Num(passing)/Num(passing+failing))! + $Colorful" + + @(cyan,b:Progress: $(completed:percent())) + + ":print() + +func main(clean=no): + clear_screen() + $Colorful" + $\n@(bold,green:Hello and welcome to the Tomo Koans program!) + + We're going to run through some programs that don't work + and you'll be fixing them up! + + I hope you have fun! + + ":print() + + editor := if (./editor.txt):exists(): + (./editor.txt):read()! + else: + e := ask("What command line text editor do you want to use? ")! + (./editor.txt):write(e) + e + + $Colorful"You're using @(b:$editor)$\n":print() + + if clean: + (./lessons):remove() + + $Shell" + cp -r lesson-templates lessons + ":run():or_fail("Could not make lessons directory") + + repeat: + ask_continue() + clear_screen() + summarize_tests() + choice := ask("Choose a test or (q)uit: ") or stop repeat + if choice == "q" or choice == "Q": stop repeat + + if choice == "": + for i,l in LESSONS: + if not l:get_result():is_success(): + choice = Text(i) + stop + + n := Int.parse(choice) or (do: + $Colorful"@(red:I don't know what that means! Type a test number or 'q'.)":print() + skip repeat + ) + + if n < 1 or n > LESSONS.length: + $Colorful"@(red:That's not a valid test number!)":print() + skip repeat + + lesson := LESSONS[n] + clear_screen() + + repeat: + $Colorful" + + @(yellow,b,u:Lesson $n: "$(lesson.description)") + Here's what we have right now: + + ":print() + + result := lesson:get_result() + result:print() + if result:is_success(): + stop repeat + + summarize_tests(highlight=lesson.file) + action := ask("That didn't go so well. (e)dit the file and try again? Or (Q)uit? ") + if action: + if action:lower() == "e": + $Shell" + $editor $(lesson.file) + ":run():or_fail("Could not open editor $editor") + skip repeat + + $Colorful"Goodbye! Come back again soon!":print() + return + + $Colorful" + @(green,b:✨ Good job, that succeeded! ✨) + + ":print() + + clear_screen() + $Colorful"@(b:Goodbye! Come back again soon!)":print() diff --git a/lesson-templates/lesson-01.tm b/lesson-templates/lesson-01.tm new file mode 100644 index 0000000..5794842 --- /dev/null +++ b/lesson-templates/lesson-01.tm @@ -0,0 +1,5 @@ +# This is a simple "Hello world" program. +# Edit it so it prints the text "Hello world": + +func main(): + say("Goodbye moon") diff --git a/lesson-templates/lesson-02.tm b/lesson-templates/lesson-02.tm new file mode 100644 index 0000000..205bdd5 --- /dev/null +++ b/lesson-templates/lesson-02.tm @@ -0,0 +1,22 @@ +func main(): + say(" + Let's learn about text concatenation! + It uses the `++` operator: + ") + + greeting := "Hello " + + ############################################################## + ###################### EDIT BELOW HERE ####################### + ############################################################## + + your_text := greeting ++ "space" + + ############################################################## + ################## DO NOT EDIT AFTER HERE #################### + ############################################################## + + say(your_text) + + >> your_text + = "Hello world"