From 5e51221cb8abf03069075d436014f6e374cc557d Mon Sep 17 00:00:00 2001 From: Cael Date: Sun, 18 Feb 2024 12:04:56 +0800 Subject: [PATCH] feat: add more detailed python test code --- backend/Cargo.lock | 38 ++-- backend/example/book.toml | 2 + backend/example/src/SUMMARY.md | 10 +- backend/example/src/intro.md | 17 +- backend/example/src/python/basics.md | 35 ++++ backend/example/src/python/get-started.md | 25 +++ backend/example/src/python/intro.md | 13 ++ backend/example/src/python/operators.md | 172 ++++++++++++++++ .../example/src/python/variable-and-types.md | 186 ++++++++++++++++++ backend/src/repl.rs | 44 ++--- 10 files changed, 489 insertions(+), 53 deletions(-) create mode 100644 backend/example/src/python/basics.md create mode 100644 backend/example/src/python/get-started.md create mode 100644 backend/example/src/python/intro.md create mode 100644 backend/example/src/python/operators.md create mode 100644 backend/example/src/python/variable-and-types.md diff --git a/backend/Cargo.lock b/backend/Cargo.lock index e08892e..13d1276 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -169,9 +169,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" [[package]] name = "byteorder" @@ -214,18 +214,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", @@ -236,9 +236,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299353be8209bd133b049bf1c63582d184a8b39fd9c04f15fe65f50f88bdfe6c" +checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c" dependencies = [ "clap", ] @@ -457,7 +457,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1088,7 +1088,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1157,7 +1157,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1308,7 +1308,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.48", + "syn 2.0.49", "walkdir", ] @@ -1394,7 +1394,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1524,9 +1524,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" dependencies = [ "proc-macro2", "quote", @@ -1583,7 +1583,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1626,7 +1626,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1888,7 +1888,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "wasm-bindgen-shared", ] @@ -1910,7 +1910,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/backend/example/book.toml b/backend/example/book.toml index cf2ecc6..eddccf7 100644 --- a/backend/example/book.toml +++ b/backend/example/book.toml @@ -46,5 +46,7 @@ expand = true heading-split-level = 3 copy-js = true +[output.markdown] + [preprocessor.repl] command = "target/release/mdbook-repl" diff --git a/backend/example/src/SUMMARY.md b/backend/example/src/SUMMARY.md index 976f211..80f61ca 100644 --- a/backend/example/src/SUMMARY.md +++ b/backend/example/src/SUMMARY.md @@ -1,3 +1,11 @@ # Summary -- [Intro](./intro.md) +- [Intro](intro.md) +- [Python](python/intro.md) + - [Get Started](python/get-started.md) + - [Basics](python/basics.md) + - [Variable and Types](python/variable-and-types.md) + - [Operators](python/operators.md) +- [C]() +- [C++]() +- [Javascript]() diff --git a/backend/example/src/intro.md b/backend/example/src/intro.md index 1f8fcd6..0dbc7b5 100644 --- a/backend/example/src/intro.md +++ b/backend/example/src/intro.md @@ -1,18 +1,15 @@ # Mdbook REPL -This is a python **realtime** playground which uses pyodide **webassembly** to run python code in the browser. So you can run python code in the browser without any server. +This is a [mdbook](https://rust-lang.github.io/mdBook) playground which uses **webassembly** to execute code in the browser. So you can run code in the browser without any server. -Below is a simple example, you can run the code and see the output. +This is inspired by mdbook rust playground, but it is not limited to rust. Nowdays, webassembly is very powerful, so I learned it and try to make a playground for multiple languages with mdbook. -**Python** +Now only **Python** is supported, maybe I will add more languages in the future. ```python -# This is a default python code -import calendar +# Python -yy = 2024 # year -mm = 2 # month - -# display the calendar -print(calendar.month(yy, mm)) +print("Hello, World!") ``` + +Tell me if you have any ideas or suggestions. diff --git a/backend/example/src/python/basics.md b/backend/example/src/python/basics.md new file mode 100644 index 0000000..5aab7d2 --- /dev/null +++ b/backend/example/src/python/basics.md @@ -0,0 +1,35 @@ +# Basics + +## encode + +By default, Python source files are encoded in **UTF-8** and all strings are unicode strings. Of course, you can also specify different encodings for the source code files: + +```plaintext +# -*- coding: cp-1252 -*- +``` + +The above definition allows the use of character encoding from the Windows-1252 character set in the source file, corresponding to Bulgarian, Belarusian, Macedonian, Russian, Serbian. + +## comments + +Python uses the hash character `#` to start a comment. The comment ends at the end of the line. + +```python +# This is a comment + +print("Hello, World!") # This is also a comment +``` + +## multi-line comments + +Python does not have a syntax for multi-line comments, but you can use triple quotes: + +```python +""" +This is a comment +written in +more than just one line +""" + +print("Hello, World!") +``` diff --git a/backend/example/src/python/get-started.md b/backend/example/src/python/get-started.md new file mode 100644 index 0000000..a60eb79 --- /dev/null +++ b/backend/example/src/python/get-started.md @@ -0,0 +1,25 @@ +# Get Started + +## Who should read this tutorial? + +This tutorial is for developers who want to learn the Python programming language from scratch. Of course, this tutorial will also provide some in-depth modules to give you a better understanding of Python applications. + +## The first Python program + +For most programming languages, the first code to get started is "Hello World!", and the following code is to output "Hello World!" in Python: + +```python +# Python + +print("Hello, World!") +``` + +A common Python file extension is .py. + +You can save the above code in a hello.py file and execute the script file with python commands. + +```bash +python hello.py +``` + +You should see the output "Hello, World!" in the terminal or you can run the code in the browser by clicking the **Play** button below. diff --git a/backend/example/src/python/intro.md b/backend/example/src/python/intro.md new file mode 100644 index 0000000..706625b --- /dev/null +++ b/backend/example/src/python/intro.md @@ -0,0 +1,13 @@ +# Python + +Python is a widely used high-level programming language for general-purpose programming, created by Guido van Rossum and first released in 1991. + +Python features a dynamic type system and automatic memory management and supports multiple programming paradigms, including object-oriented, imperative, functional programming, and procedural styles. It has a large and comprehensive standard library. + +You can learn some basics of Python in the following sections. + +```python +# Python + +print("Hello, World!") +``` diff --git a/backend/example/src/python/operators.md b/backend/example/src/python/operators.md new file mode 100644 index 0000000..ba6d699 --- /dev/null +++ b/backend/example/src/python/operators.md @@ -0,0 +1,172 @@ +# Operators + +Python language supports the following types of operators: + +- Arithmetic operators +- Comparison operators +- Logical operators +- Bitwise operators +- Assignment operators +- Identity operators +- Membership operators +- Bitwise operators + +## arithmetic operators + +Arithmetic operators are used with numeric values to perform common mathematical operations: + +```python +x = 5 + +print(x + 3) # addition + +print(x - 3) # subtraction + +print(x * 3) # multiplication + +print(x / 3) # division + +print(x % 3) # modulus + +print(x ** 3) # exponentiation + +print(x // 3) # floor division +``` + +## comparison operators + +Comparison operators are used to compare two values: + +```python +x = 5 +y = 3 + +print(x == y) # equal + +print(x != y) # not equal + +print(x > y) # greater than + +print(x < y) # less than + +print(x >= y) # greater than or equal to + +print(x <= y) # less than or equal to +``` + +## logical operators + +Logical operators are used to combine conditional statements: + +```python +x = 5 + +print(x > 3 and x < 10) # and + +print(x > 3 or x < 4) # or + +print(not(x > 3 and x < 10)) # not +``` + +## bitwise operators + +Bitwise operators are used to compare (binary) numbers: + +```python +x = 5 +y = 3 + +print(x & y) # AND + +print(x | y) # OR + +print(x ^ y) # XOR + +print(~x) # NOT + +print(x << 2) # Zero fill left shift + +print(x >> 2) # Signed right shift +``` + +## assignment operators + +Assignment operators are used to assign values to variables: + +```python +x = 5 + +x += 3 # x = x + 3 + +x -= 3 # x = x - 3 + +x *= 3 # x = x * 3 + +x /= 3 # x = x / 3 + +x %= 3 # x = x % 3 + +x //= 3 # x = x // 3 + +x **= 3 # x = x ** 3 + +x &= 3 # x = x & 3 + +x |= 3 # x = x | 3 + +x ^= 3 # x = x ^ 3 + +x >>= 3 # x = x >> 3 + +x <<= 3 # x = x << 3 +``` + +## identity operators + +Identity operators are used to compare the objects, not if they are equal, but if they are actually the same object, with the same memory location: + +```python +x = ["apple", "banana"] +y = ["apple", "banana"] + +z = x + +print(x is z) # returns True because z is the same object as x + +print(x is y) # returns False because x is not the same object as y, even if they have the same content + +print(x == y) # to demonstrate the difference betweeen "is" and "==": this comparison returns True because x is equal to y +``` + +## membership operators + +Membership operators are used to test if a sequence is presented in an object: + +```python +x = ["apple", "banana"] + +print("banana" in x) # returns True because a sequence with the value "banana" is in the list + +print("pineapple" not in x) # returns True because a sequence with the value "pineapple" is not in the list +``` + +## bitwise operators + +Bitwise operators are used to compare (binary) numbers: + +```python +x = 5 +y = 3 + +print(x & y) # AND + +print(x | y) # OR + +print(x ^ y) # XOR + +print(~x) # NOT + +print(x << 2) # Zero fill left shift + +print(x >> 2) # Signed right shift +``` diff --git a/backend/example/src/python/variable-and-types.md b/backend/example/src/python/variable-and-types.md new file mode 100644 index 0000000..ee8935f --- /dev/null +++ b/backend/example/src/python/variable-and-types.md @@ -0,0 +1,186 @@ +# Variable and Types + +## variables + +Python has no command for declaring a variable. A variable is created the moment you first assign a value to it. + +```python +x = 5 +y = "John" + +print(x) +print(y) +``` + +Variables do not need to be declared with any particular type and can even change type after they have been set. + +```python +x = 4 # x is of type int +print(x) + +x = "Sally" # x is now of type str +print(x) +``` + +## data types + +Python has the following data types built-in by default, in these categories: + +- Text Type: `str` +- Numeric Types: `int`, `float`, `complex` +- Sequence Types: `list`, `tuple`, `range` +- Mapping Type: `dict` +- Set Types: `set`, `frozenset` +- Boolean Type: `bool` +- Binary Types: `bytes`, `bytearray`, `memoryview` +- None Type: `NoneType` +- Type Type: `type` + +## numbers + +There are three numeric types in Python: + +- `int` +- `float` +- `complex` + +```python +x = 1 # int +y = 2.8 # float +z = 1j # complex + +print(x) +print(y) +print(z) +``` + +## strings + +Strings in Python are surrounded by either single quotation marks, or double quotation marks. + +```python +a = "Hello, World!" +b = 'Hello, World!' + +print(a) +print(b) +``` + +You can assign a multiline string to a variable by using three quotes: + +```python +a = """Lorem ipsum dolor sit amet, +consectetur adipiscing elit, +sed do eiusmod tempor incididunt +ut labore et dolore magna aliqua.""" + +print(a) +``` + +## booleans + +Booleans represent one of two values: `True` or `False`. + +```python +print(10 > 9) # True +print(10 == 9) # False +print(10 < 9) # False +``` + +## lists + +Lists are used to store multiple items in a single variable. + +```python +thislist = ["apple", "banana", "cherry"] + +print(thislist) +``` + +## tuples + +A tuple is a collection which is ordered and unchangeable. In Python tuples are written with round brackets. + +```python +thistuple = ("apple", "banana", "cherry") + +print(thistuple) +``` + +## sets + +Sets are used to store multiple items in a single variable. + +```python +thisset = {"apple", "banana", "cherry"} + +print(thisset) +``` + +## dictionaries + +Dictionaries are used to store data values in key:value pairs. + +```python +thisdict = { + "brand": "Ford", + "model": "Mustang", + "year": 1964 +} + +print(thisdict) +``` + +## type casting + +You can specify a variable type by using a constructor function: + +```python +x = str(3) # x will be '3' +y = int(3) # y will be 3 +z = float(3) # z will be 3.0 + +print(x) +print(y) +print(z) +``` + +## None + +In Python, the `None` keyword is used to define a null value, or no value at all. + +```python + +x = None +print(x) +``` + +## type() + +You can get the data type of any object by using the `type()` function: + +```python +x = 5 + +print(type(x)) +``` + +## isinstance() + +To check if an object is of a certain data type, you can use the `isinstance()` function: + +```python +x = 5 + +print(isinstance(x, int)) +``` + +## id() + +The `id()` function returns a unique id for the specified object. + +```python +x = ("apple", "banana", "cherry") + +print(id(x)) +``` diff --git a/backend/src/repl.rs b/backend/src/repl.rs index a2aa547..c0a2309 100644 --- a/backend/src/repl.rs +++ b/backend/src/repl.rs @@ -25,6 +25,26 @@ fn get_asset(name: &str) -> String { std::str::from_utf8(file.data.as_ref()).unwrap().to_string() } +fn render_repls(content: &str) -> String { + let re = Regex::new(r"(?s)```(py|python)\n(.*?)```").unwrap(); + + re.replace_all(content, |caps: ®ex::Captures| { + let id = Uuid::new_v4().to_string(); + let lang = caps.get(1).unwrap().as_str(); + let code = caps.get(0).unwrap().as_str().trim(); + + if lang == "py" || lang == "python" { + get_asset("repl.html") + .replace("{id}", &id) + .replace("{code}", &code) + .replace("{lang}", "python") + } else { + code.to_string() + } + }) + .to_string() +} + impl Preprocessor for Repl { fn name(&self) -> &str { "mdbook-repl" @@ -33,31 +53,9 @@ impl Preprocessor for Repl { fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result { book.for_each_mut(|item| { if let mdbook::book::BookItem::Chapter(chapter) = item { - let re = Regex::new(r"```(\w+)\n((?s:.*?))```").unwrap(); - - if !re.is_match(&chapter.content) { - return; - } - + chapter.content = render_repls(&chapter.content); chapter.content.push_str(&get_asset("script.html")); chapter.content.insert_str(0, &get_asset("style.html")); - - chapter.content = re - .replace_all(&chapter.content, |caps: ®ex::Captures| { - let id = Uuid::new_v4().to_string(); - let lang = caps.get(1).unwrap().as_str(); - let code = caps.get(0).unwrap().as_str().trim(); - - if lang == "python" { - get_asset("repl.html") - .replace("{id}", &id) - .replace("{code}", code) - .replace("{lang}", "python") - } else { - code.to_string() - } - }) - .to_string() } }); Ok(book)