mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
check-md: verify code example formatting (#7143)
This commit is contained in:
parent
0d28f12c54
commit
8adb1acf31
14
README.md
14
README.md
@ -24,7 +24,7 @@
|
||||
## Key Features of V
|
||||
|
||||
- Simplicity: the language can be learned in less than an hour
|
||||
- Fast compilation: ≈80k loc/s with a Clang backend,
|
||||
- Fast compilation: ≈80k loc/s with a Clang backend,
|
||||
≈1 million loc/s with x64 and tcc backends *(Intel i5-7500, SSD, no optimization)*
|
||||
- Easy to develop: V compiles itself in less than a second
|
||||
- Performance: as fast as C (V's main backend compiles to human readable C)
|
||||
@ -81,7 +81,7 @@ v up
|
||||
|
||||
### C compiler
|
||||
|
||||
It's recommended to use Clang or GCC or Visual Studio.
|
||||
It's recommended to use Clang or GCC or Visual Studio.
|
||||
If you are doing development, you most likely already have one of those installed.
|
||||
|
||||
Otherwise, follow these instructions:
|
||||
@ -90,8 +90,8 @@ Otherwise, follow these instructions:
|
||||
|
||||
- [Installing a C compiler on Windows](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows)
|
||||
|
||||
However, if none is found when running `make` on Linux or Windows,
|
||||
TCC would be downloaded and set as an alternative C backend.
|
||||
However, if none is found when running `make` on Linux or Windows,
|
||||
TCC would be downloaded and set as an alternative C backend.
|
||||
It's very lightweight (several MB) so this shouldn't take too long.
|
||||
|
||||
### Symlinking
|
||||
@ -227,9 +227,9 @@ https://github.com/vlang/ui
|
||||
|
||||
```v
|
||||
fn main() {
|
||||
for i in 0..3 {
|
||||
println('Hello from V.js')
|
||||
}
|
||||
for i in 0 .. 3 {
|
||||
println('Hello from V.js')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -102,7 +102,6 @@ fn eline(file_path string, lnumber int, column int, message string) string {
|
||||
return btext('$file_path:${lnumber + 1}:${column + 1}:') + btext(rtext(' error: $message'))
|
||||
}
|
||||
|
||||
//
|
||||
const (
|
||||
default_command = 'compile'
|
||||
)
|
||||
@ -190,16 +189,23 @@ fn (mut f MDFile) check_examples() (int, int) {
|
||||
vfile := os.join_path(os.temp_dir(), 'check_${fname}_example_${e.sline}__${e.eline}__${uid}.v')
|
||||
mut should_cleanup_vfile := true
|
||||
// eprintln('>>> checking example $vfile ...')
|
||||
vcontent := e.text.join('\n')
|
||||
vcontent := e.text.join('\n') + '\n'
|
||||
os.write_file(vfile, vcontent) or { panic(err) }
|
||||
mut acommands := e.command.split(' ')
|
||||
nofmt := 'nofmt' in acommands
|
||||
for command in acommands {
|
||||
match command {
|
||||
'compile' {
|
||||
res := os.system('"$vexe" -w -Wfatal-errors -o x.c $vfile')
|
||||
os.rm('x.c') or { }
|
||||
if res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, 'example failed to compile'))
|
||||
fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') }
|
||||
if res != 0 || fmt_res != 0 {
|
||||
if res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, 'example failed to compile'))
|
||||
}
|
||||
if fmt_res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, 'example is not formatted'))
|
||||
}
|
||||
eprintln(vcontent)
|
||||
should_cleanup_vfile = false
|
||||
errors++
|
||||
@ -209,8 +215,14 @@ fn (mut f MDFile) check_examples() (int, int) {
|
||||
}
|
||||
'live' {
|
||||
res := os.system('"$vexe" -w -Wfatal-errors -live -o x.c $vfile')
|
||||
if res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, 'example failed to compile with -live'))
|
||||
fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') }
|
||||
if res != 0 || fmt_res != 0 {
|
||||
if res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, 'example failed to compile with -live'))
|
||||
}
|
||||
if fmt_res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, 'example is not formatted'))
|
||||
}
|
||||
eprintln(vcontent)
|
||||
should_cleanup_vfile = false
|
||||
errors++
|
||||
@ -232,8 +244,14 @@ fn (mut f MDFile) check_examples() (int, int) {
|
||||
}
|
||||
'oksyntax' {
|
||||
res := os.system('"$vexe" -w -Wfatal-errors -check-syntax $vfile')
|
||||
if res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, '`oksyntax` example with invalid syntax'))
|
||||
fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') }
|
||||
if res != 0 || fmt_res != 0 {
|
||||
if res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, '`oksyntax` example with invalid syntax'))
|
||||
}
|
||||
if fmt_res != 0 {
|
||||
eprintln(eline(f.path, e.sline, 0, '`oksyntax` example is not formatted'))
|
||||
}
|
||||
eprintln(vcontent)
|
||||
should_cleanup_vfile = false
|
||||
errors++
|
||||
@ -252,6 +270,7 @@ fn (mut f MDFile) check_examples() (int, int) {
|
||||
}
|
||||
oks++
|
||||
}
|
||||
'nofmt' {}
|
||||
else {
|
||||
eprintln(eline(f.path, e.sline, 0, 'unrecognized command: "$command", use one of: wip/ignore/compile/failcompile/oksyntax/badsyntax'))
|
||||
should_cleanup_vfile = false
|
||||
|
995
doc/docs.md
995
doc/docs.md
File diff suppressed because it is too large
Load Diff
@ -75,8 +75,11 @@ pub fn (mut app App) index() vweb.Result {
|
||||
return vweb.Result{}
|
||||
}
|
||||
|
||||
pub fn (app &App) init() {}
|
||||
pub fn (app &App) init_once() {}
|
||||
pub fn (app &App) init() {
|
||||
}
|
||||
|
||||
pub fn (app &App) init_once() {
|
||||
}
|
||||
```
|
||||
|
||||
Run it with
|
||||
@ -103,6 +106,8 @@ no routing rules either:
|
||||
|
||||
```v oksyntax
|
||||
import vweb
|
||||
import time
|
||||
|
||||
fn (mut app App) time() vweb.Result {
|
||||
app.vweb.text(time.now().format())
|
||||
return vweb.Result{}
|
||||
@ -341,10 +346,11 @@ Create `new.html`:
|
||||
|
||||
```v oksyntax
|
||||
import vweb
|
||||
|
||||
pub fn (mut app App) new_article() vweb.Result {
|
||||
title := app.vweb.form['title']
|
||||
text := app.vweb.form['text']
|
||||
if title == '' || text == '' {
|
||||
if title == '' || text == '' {
|
||||
app.vweb.text('Empty text/title')
|
||||
return vweb.Result{}
|
||||
}
|
||||
@ -380,6 +386,8 @@ in V is very simple:
|
||||
|
||||
```v oksyntax
|
||||
import vweb
|
||||
import json
|
||||
|
||||
pub fn (mut app App) articles() vweb.Result {
|
||||
articles := app.find_all_articles()
|
||||
app.vweb.json(json.encode(articles))
|
||||
|
@ -1,42 +1,43 @@
|
||||
Example usage of this module:
|
||||
```
|
||||
```v
|
||||
import benchmark
|
||||
|
||||
mut bmark := benchmark.new_benchmark()
|
||||
// by default the benchmark will be verbose, i.e. it will include timing information
|
||||
// if you want it to be silent, set bmark.verbose = false
|
||||
for {
|
||||
bmark.step() // call this when you want to advance the benchmark.
|
||||
// The timing info in bmark.step_message will be measured starting from the last call to bmark.step
|
||||
....
|
||||
|
||||
//bmark.fail() // call this if the step failed
|
||||
//bmark.step_message(('failed')
|
||||
|
||||
bmark.ok() // call this when the step succeeded
|
||||
println( bmark.step_message('ok')
|
||||
bmark.step() // call this when you want to advance the benchmark.
|
||||
// The timing info in bmark.step_message will be measured starting from the last call to bmark.step
|
||||
// ....
|
||||
// bmark.fail() // call this if the step failed
|
||||
// bmark.step_message(('failed')
|
||||
bmark.ok() // call this when the step succeeded
|
||||
println(bmark.step_message('ok'))
|
||||
}
|
||||
bmark.stop() // call when you want to finalize the benchmark
|
||||
println( bmark.total_message('remarks about the benchmark') )
|
||||
bmark.stop()
|
||||
// call when you want to finalize the benchmark
|
||||
println(bmark.total_message('remarks about the benchmark'))
|
||||
```
|
||||
|
||||
benchmark.start() and b.measure() are convenience methods,
|
||||
intended to be used in combination. Their goal is to make
|
||||
benchmarking of small snippets of code as *short*, easy to
|
||||
write, and then to read and analyze the results, as possible.
|
||||
|
||||
Example:
|
||||
```v
|
||||
import time
|
||||
import benchmark
|
||||
mut b := benchmark.start()
|
||||
|
||||
mut b := benchmark.start()
|
||||
// your code section 1 ...
|
||||
time.sleep_ms(1500)
|
||||
b.measure('code_1')
|
||||
|
||||
// your code section 2 ...
|
||||
time.sleep_ms(500)
|
||||
b.measure('code_2')
|
||||
```
|
||||
|
||||
... which will produce on stdout something like this:
|
||||
```text
|
||||
SPENT 1500.063 ms in code_1
|
||||
|
@ -5,13 +5,13 @@ import encoding.csv
|
||||
|
||||
data := 'x,y\na,b,c\n'
|
||||
mut parser := csv.new_reader(data)
|
||||
|
||||
// read each line
|
||||
for {
|
||||
items := parser.read() or {break}
|
||||
println(items)
|
||||
items := parser.read() or { break }
|
||||
println(items)
|
||||
}
|
||||
```
|
||||
|
||||
It prints:
|
||||
```
|
||||
['x', 'y']
|
||||
|
@ -35,20 +35,20 @@ fn cb(receiver voidptr, args voidptr, sender voidptr) {
|
||||
|
||||
// Since V can map structs to voidptr, this also works
|
||||
struct ClickEvent {
|
||||
x int
|
||||
y int
|
||||
x int
|
||||
y int
|
||||
}
|
||||
|
||||
// Example case where publisher sends ClickEvent as args.
|
||||
fn on_press(receiver voidptr, e &ClickEvent, sender voidptr){
|
||||
println(e.x)
|
||||
//your code here...
|
||||
fn on_press(receiver voidptr, e &ClickEvent, sender voidptr) {
|
||||
println(e.x)
|
||||
// your code here...
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
For **usage across modules**
|
||||
For **usage across modules**
|
||||
[check the example](https://github.com/vlang/v/tree/master/examples/eventbus).
|
||||
|
||||
_Note: As a general rule, you will need to **subscribe before publishing**._
|
||||
@ -57,25 +57,26 @@ _Note: As a general rule, you will need to **subscribe before publishing**._
|
||||
|
||||
```v oksyntax
|
||||
module main
|
||||
|
||||
import eventbus
|
||||
|
||||
// initialize it globally
|
||||
const (
|
||||
eb = eventbus.new()
|
||||
eb = eventbus.new()
|
||||
)
|
||||
|
||||
fn main(){
|
||||
// get a mutable reference to the subscriber
|
||||
fn main() {
|
||||
// get a mutable reference to the subscriber
|
||||
mut sub := eb.subscriber
|
||||
// subscribe to the 'error' event
|
||||
sub.subscribe("error", on_error)
|
||||
// start the work
|
||||
// subscribe to the 'error' event
|
||||
sub.subscribe('error', on_error)
|
||||
// start the work
|
||||
do_work()
|
||||
}
|
||||
|
||||
// the event handler
|
||||
fn on_error(receiver voidptr, e &Error, work &Work) {
|
||||
println('error occured on ${work.hours}. Error: ${e.message}')
|
||||
println('error occured on ${work.hours}. Error: $e.message')
|
||||
}
|
||||
```
|
||||
|
||||
@ -84,20 +85,20 @@ fn on_error(receiver voidptr, e &Error, work &Work) {
|
||||
```v oksyntax
|
||||
module main
|
||||
|
||||
struct Work{
|
||||
hours int
|
||||
struct Work {
|
||||
hours int
|
||||
}
|
||||
|
||||
struct Error {
|
||||
message string
|
||||
message string
|
||||
}
|
||||
|
||||
fn do_work(){
|
||||
work := Work{20}
|
||||
// get a mutable Params instance & put some data into it
|
||||
error := &Error{"Error: no internet connection."}
|
||||
// publish the event
|
||||
eb.publish("error", work, error)
|
||||
fn do_work() {
|
||||
work := Work{20}
|
||||
// get a mutable Params instance & put some data into it
|
||||
error := &Error{'Error: no internet connection.'}
|
||||
// publish the event
|
||||
eb.publish('error', work, error)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -160,20 +160,17 @@ that is an `[]int` inside the `RE` struct.
|
||||
**example:**
|
||||
|
||||
```v oksyntax
|
||||
text := "cpaz cpapaz cpapapaz"
|
||||
query:= r"(c(pa)+z ?)+"
|
||||
text := 'cpaz cpapaz cpapapaz'
|
||||
query := r'(c(pa)+z ?)+'
|
||||
mut re := regex.regex_opt(query) or { panic(err) }
|
||||
|
||||
println(re.get_query())
|
||||
// #0(c#1(pa)+z ?)+ // #0 and #1 are the ids of the groups, are shown if re.debug is 1 or 2
|
||||
|
||||
start, end := re.match_string(text)
|
||||
// [start=0, end=20] match => [cpaz cpapaz cpapapaz]
|
||||
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println("${gi/2} :[${text[re.groups[gi]..re.groups[gi+1]]}]")
|
||||
println('${gi / 2} :[${text[re.groups[gi]..re.groups[gi + 1]]}]')
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
@ -260,45 +257,42 @@ If the space ends no error is raised, further records will not be saved.
|
||||
```v oksyntax
|
||||
fn example2() {
|
||||
test_regex()
|
||||
|
||||
text := "tst: 01,23,45 ,56, 78"
|
||||
query:= r".*:(\s*\d+[\s,]*)+"
|
||||
|
||||
text := 'tst: 01,23,45 ,56, 78'
|
||||
query := r'.*:(\s*\d+[\s,]*)+'
|
||||
mut re := new() or { panic(err) }
|
||||
//re.debug = 2
|
||||
re.group_csave = [-1].repeat(3*20+1) // we expect max 20 records
|
||||
|
||||
re.compile_opt(query) or { println(err) return }
|
||||
|
||||
q_str := re.get_query()
|
||||
println("Query: $q_str")
|
||||
|
||||
start, end := re.match_string(text)
|
||||
if start < 0 {
|
||||
println("ERROR : ${re.get_parse_error_string(start)}, $start")
|
||||
} else {
|
||||
println("found in [$start, $end] => [${text[start..end]}]")
|
||||
}
|
||||
|
||||
// groups capture
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println("${gi/2} ${re.groups[gi]},${re.groups[gi+1]} :[${text[re.groups[gi]..re.groups[gi+1]]}]")
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
|
||||
// continuous saving
|
||||
gi = 0
|
||||
println("num: ${re.group_csave[0]}")
|
||||
for gi < re.group_csave[0] {
|
||||
id := re.group_csave[1+gi*3]
|
||||
st := re.group_csave[1+gi*3+1]
|
||||
en := re.group_csave[1+gi*3+2]
|
||||
println("cg id: ${id} [${st}, ${en}] => [${text[st..en]}]")
|
||||
gi++
|
||||
}
|
||||
// re.debug = 2
|
||||
re.group_csave = [-1].repeat(3 * 20 + 1) // we expect max 20 records
|
||||
re.compile_opt(query) or {
|
||||
println(err)
|
||||
return
|
||||
}
|
||||
q_str := re.get_query()
|
||||
println('Query: $q_str')
|
||||
start, end := re.match_string(text)
|
||||
if start < 0 {
|
||||
println('ERROR : ${re.get_parse_error_string(start)}, $start')
|
||||
} else {
|
||||
println('found in [$start, $end] => [${text[start..end]}]')
|
||||
}
|
||||
// groups capture
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println('${gi / 2} ${re.groups[gi]},${re.groups[gi + 1]} :[${text[re.groups[gi]..re.groups[gi +
|
||||
1]]}]')
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
// continuous saving
|
||||
gi = 0
|
||||
println('num: ${re.group_csave[0]}')
|
||||
for gi < re.group_csave[0] {
|
||||
id := re.group_csave[1 + gi * 3]
|
||||
st := re.group_csave[1 + gi * 3 + 1]
|
||||
en := re.group_csave[1 + gi * 3 + 2]
|
||||
println('cg id: $id [$st, $en] => [${text[st..en]}]')
|
||||
gi++
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -333,64 +327,61 @@ example:
|
||||
|
||||
```v ignore
|
||||
import regex
|
||||
|
||||
fn main() {
|
||||
test_regex()
|
||||
|
||||
text := "http://www.ciao.mondo/hello/pippo12_/pera.html"
|
||||
query:= r"(?P<format>https?)|(?:ftps?)://(?P<token>[\w_]+.)+"
|
||||
|
||||
text := 'http://www.ciao.mondo/hello/pippo12_/pera.html'
|
||||
query := r'(?P<format>https?)|(?:ftps?)://(?P<token>[\w_]+.)+'
|
||||
mut re := new()
|
||||
re.debug = 2
|
||||
|
||||
// must provide an array of the right size if want the continuos saving of the groups
|
||||
re.group_csave = [-1].repeat(3*20+1)
|
||||
|
||||
re.compile_opt(query) or { println(err) return }
|
||||
|
||||
q_str := re.get_query()
|
||||
println("O.Query: $query")
|
||||
println("Query : $q_str")
|
||||
|
||||
re.debug = 0
|
||||
start, end := re.match_string(text)
|
||||
if start < 0 {
|
||||
err_str := re.get_parse_error_string(start)
|
||||
println("ERROR : $err_str, $start")
|
||||
} else {
|
||||
text1 := text[start..end]
|
||||
println("found in [$start, $end] => [$text1]")
|
||||
}
|
||||
|
||||
// groups
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println("${gi/2} ${re.groups[gi]},${re.groups[gi+1]} :[${text[re.groups[gi]..re.groups[gi+1]]}]")
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
// continuous saving
|
||||
gi = 0
|
||||
println("num of group item saved: ${re.group_csave[0]}")
|
||||
for gi < re.group_csave[0] {
|
||||
id := re.group_csave[1+gi*3]
|
||||
st := re.group_csave[1+gi*3+1]
|
||||
en := re.group_csave[1+gi*3+2]
|
||||
println("cg id: ${id} [${st}, ${en}] => [${text[st..en]}]")
|
||||
gi++
|
||||
}
|
||||
println("raw array: ${re.group_csave[0..gi*3+2-1]}")
|
||||
|
||||
// named capturing groups
|
||||
println("named capturing groups:")
|
||||
for g_name in re.group_map.keys() {
|
||||
s,e := re.get_group(g_name)
|
||||
if s >= 0 && e > s {
|
||||
println("'${g_name}':[$s, $e] => '${text[s..e]}'")
|
||||
} else {
|
||||
println("Group [${g_name}] doesn't exist.")
|
||||
}
|
||||
}
|
||||
re.group_csave = [-1].repeat(3 * 20 + 1)
|
||||
re.compile_opt(query) or {
|
||||
println(err)
|
||||
return
|
||||
}
|
||||
q_str := re.get_query()
|
||||
println('O.Query: $query')
|
||||
println('Query : $q_str')
|
||||
re.debug = 0
|
||||
start, end := re.match_string(text)
|
||||
if start < 0 {
|
||||
err_str := re.get_parse_error_string(start)
|
||||
println('ERROR : $err_str, $start')
|
||||
} else {
|
||||
text1 := text[start..end]
|
||||
println('found in [$start, $end] => [$text1]')
|
||||
}
|
||||
// groups
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println('${gi / 2} ${re.groups[gi]},${re.groups[gi + 1]} :[${text[re.groups[gi]..re.groups[gi +
|
||||
1]]}]')
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
// continuous saving
|
||||
gi = 0
|
||||
println('num of group item saved: ${re.group_csave[0]}')
|
||||
for gi < re.group_csave[0] {
|
||||
id := re.group_csave[1 + gi * 3]
|
||||
st := re.group_csave[1 + gi * 3 + 1]
|
||||
en := re.group_csave[1 + gi * 3 + 2]
|
||||
println('cg id: $id [$st, $en] => [${text[st..en]}]')
|
||||
gi++
|
||||
}
|
||||
println('raw array: ${re.group_csave[0..gi * 3 + 2 - 1]}')
|
||||
// named capturing groups
|
||||
println('named capturing groups:')
|
||||
for g_name in re.group_map.keys() {
|
||||
s, e := re.get_group(g_name)
|
||||
if s >= 0 && e > s {
|
||||
println("'$g_name':[$s, $e] => '${text[s..e]}'")
|
||||
} else {
|
||||
println("Group [$g_name] doesn't exist.")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -530,17 +521,14 @@ This module has few small utilities to help the writing of regex expressions.
|
||||
the following example code show how to visualize the syntax errors in the compilation phase:
|
||||
|
||||
```v oksyntax
|
||||
query:= r"ciao da ab[ab-]" // there is an error, a range not closed!!
|
||||
query := r'ciao da ab[ab-]'
|
||||
// there is an error, a range not closed!!
|
||||
mut re := new()
|
||||
|
||||
re.compile_opt(query) or { println(err) }
|
||||
|
||||
// output!!
|
||||
|
||||
//query: ciao da ab[ab-]
|
||||
//err : ----------^
|
||||
//ERROR: ERR_SYNTAX_ERROR
|
||||
|
||||
// query: ciao da ab[ab-]
|
||||
// err : ----------^
|
||||
// ERROR: ERR_SYNTAX_ERROR
|
||||
```
|
||||
|
||||
### **Compiled code**
|
||||
@ -636,12 +624,12 @@ it is possible to provide an alternative output setting a custom output functio
|
||||
```v oksyntax
|
||||
// custom print function, the input will be the regex debug string
|
||||
fn custom_print(txt string) {
|
||||
println("my log: $txt")
|
||||
println('my log: $txt')
|
||||
}
|
||||
|
||||
mut re := new()
|
||||
re.log_func = custom_print // every debug output from now will call this function
|
||||
|
||||
re.log_func = custom_print
|
||||
// every debug output from now will call this function
|
||||
```
|
||||
|
||||
## Example code
|
||||
@ -652,44 +640,45 @@ Here there is a simple code to perform some basically match of strings
|
||||
struct TestObj {
|
||||
source string // source string to parse
|
||||
query string // regex query string
|
||||
s int // expected match start index
|
||||
e int // expected match end index
|
||||
s int // expected match start index
|
||||
e int // expected match end index
|
||||
}
|
||||
|
||||
const (
|
||||
tests = [
|
||||
TestObj{"this is a good.",r"this (\w+) a",0,9},
|
||||
TestObj{"this,these,those. over",r"(th[eio]se?[,. ])+",0,17},
|
||||
TestObj{"test1@post.pip.com, pera",r"[\w]+@([\w]+\.)+\w+",0,18},
|
||||
TestObj{"cpapaz ole. pippo,",r".*c.+ole.*pi",0,14},
|
||||
TestObj{"adce aabe",r"(a(ab)+)|(a(dc)+)e",0,4},
|
||||
]
|
||||
tests = [
|
||||
TestObj{'this is a good.', r'this (\w+) a', 0, 9},
|
||||
TestObj{'this,these,those. over', r'(th[eio]se?[,. ])+', 0, 17},
|
||||
TestObj{'test1@post.pip.com, pera', r'[\w]+@([\w]+\.)+\w+', 0, 18},
|
||||
TestObj{'cpapaz ole. pippo,', r'.*c.+ole.*pi', 0, 14},
|
||||
TestObj{'adce aabe', r'(a(ab)+)|(a(dc)+)e', 0, 4},
|
||||
]
|
||||
)
|
||||
|
||||
fn example() {
|
||||
for c,tst in tests {
|
||||
for c, tst in tests {
|
||||
mut re := regex.new()
|
||||
re.compile_opt(tst.query) or { println(err) continue }
|
||||
|
||||
// print the query parsed with the groups ids
|
||||
re.debug = 1 // set debug on at minimum level
|
||||
println("#${c:2d} query parsed: ${re.get_query()}")
|
||||
re.debug = 0
|
||||
|
||||
// do the match
|
||||
start, end := re.match_string(tst.source)
|
||||
if start >= 0 && end > start {
|
||||
println("#${c:2d} found in: [$start, $end] => [${tst.source[start..end]}]")
|
||||
}
|
||||
|
||||
// print the groups
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println("group ${gi/2:2d} :[${tst.source[re.groups[gi]..re.groups[gi+1]]}]")
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
println("")
|
||||
re.compile_opt(tst.query) or {
|
||||
println(err)
|
||||
continue
|
||||
}
|
||||
// print the query parsed with the groups ids
|
||||
re.debug = 1 // set debug on at minimum level
|
||||
println('#${c:2d} query parsed: $re.get_query()')
|
||||
re.debug = 0
|
||||
// do the match
|
||||
start, end := re.match_string(tst.source)
|
||||
if start >= 0 && end > start {
|
||||
println('#${c:2d} found in: [$start, $end] => [${tst.source[start..end]}]')
|
||||
}
|
||||
// print the groups
|
||||
mut gi := 0
|
||||
for gi < re.groups.len {
|
||||
if re.groups[gi] >= 0 {
|
||||
println('group ${gi / 2:2d} :[${tst.source[re.groups[gi]..re.groups[gi + 1]]}]')
|
||||
}
|
||||
gi += 2
|
||||
}
|
||||
println('')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,20 +8,19 @@ A library for working with versions in [semver][semver] format.
|
||||
import semver
|
||||
|
||||
fn main() {
|
||||
ver1 := semver.from('1.2.4') or {
|
||||
println('Invalid version')
|
||||
return
|
||||
}
|
||||
ver2 := semver.from('2.3.4') or {
|
||||
println('Invalid version')
|
||||
return
|
||||
}
|
||||
|
||||
println(ver1.gt(ver2))
|
||||
println(ver2.gt(ver1))
|
||||
println(ver1.satisfies('>=1.1.0 <2.0.0'))
|
||||
println(ver2.satisfies('>=1.1.0 <2.0.0'))
|
||||
println(ver2.satisfies('>=1.1.0 <2.0.0 || >2.2.0'))
|
||||
ver1 := semver.from('1.2.4') or {
|
||||
println('Invalid version')
|
||||
return
|
||||
}
|
||||
ver2 := semver.from('2.3.4') or {
|
||||
println('Invalid version')
|
||||
return
|
||||
}
|
||||
println(ver1.gt(ver2))
|
||||
println(ver2.gt(ver1))
|
||||
println(ver1.satisfies('>=1.1.0 <2.0.0'))
|
||||
println(ver2.satisfies('>=1.1.0 <2.0.0'))
|
||||
println(ver2.satisfies('>=1.1.0 <2.0.0 || >2.2.0'))
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -13,9 +13,10 @@ is replaced by the textual version of the following parameters.
|
||||
|
||||
```v
|
||||
import strconv
|
||||
|
||||
fn main() {
|
||||
a := "World"
|
||||
s := strconv.v_sprintf("Hello %s!", a)
|
||||
a := 'World'
|
||||
s := strconv.v_sprintf('Hello %s!', a)
|
||||
println(s)
|
||||
}
|
||||
```
|
||||
@ -49,16 +50,16 @@ The Flags field may be zero or more (in any order) of:
|
||||
|
||||
#### Width field
|
||||
|
||||
The Width field specifies a *maximum* number of characters to output,
|
||||
and is typically used to pad fixed-width fields in tabulated output,
|
||||
The Width field specifies a *maximum* number of characters to output,
|
||||
and is typically used to pad fixed-width fields in tabulated output,
|
||||
it causes truncation of oversized fields.
|
||||
|
||||
The width field may be omitted, or it may be a numeric integer value,
|
||||
or may also be specified by a parameter when indicated by an asterisk `*`.
|
||||
For example, `v_printf("%*.s", 5, my_string)` will result in ` mystring` being printed,
|
||||
The width field may be omitted, or it may be a numeric integer value,
|
||||
or may also be specified by a parameter when indicated by an asterisk `*`.
|
||||
For example, `v_printf("%*.s", 5, my_string)` will result in ` mystring` being printed,
|
||||
with a total width of 5 characters.
|
||||
|
||||
#### Length field
|
||||
#### Length field
|
||||
|
||||
The Length field can be omitted or be any of:
|
||||
|
||||
@ -71,7 +72,7 @@ The Length field can be omitted or be any of:
|
||||
| | |
|
||||
| | |
|
||||
|
||||
#### Type field
|
||||
#### Type field
|
||||
|
||||
The Type field can be any of:
|
||||
|
||||
@ -93,15 +94,15 @@ The Type field can be any of:
|
||||
various types
|
||||
|
||||
```v oksyntax
|
||||
a0 := u32(10)
|
||||
b0 := 200
|
||||
c0 := byte(12)
|
||||
s0 := "ciAo"
|
||||
a0 := u32(10)
|
||||
b0 := 200
|
||||
c0 := byte(12)
|
||||
s0 := 'ciAo'
|
||||
ch0 := `B`
|
||||
f0 := 0.312345
|
||||
f1 := 200000.0
|
||||
sc0 := "ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]"
|
||||
temp_s = strconv.v_sprintf(sc0 ,a0 ,b0 ,c0 ,s0, b0 ,f0, f1, ch0)
|
||||
f0 := 0.312345
|
||||
f1 := 200000.0
|
||||
sc0 := 'ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]'
|
||||
temp_s = strconv.v_sprintf(sc0, a0, b0, c0, s0, b0, f0, f1, ch0)
|
||||
println(temp_s)
|
||||
```
|
||||
|
||||
@ -116,8 +117,8 @@ a := byte(12)
|
||||
b := i16(13)
|
||||
c := 14
|
||||
d := i64(15)
|
||||
sc1 := "==>%hhd %hd %d %ld"
|
||||
temp_s = strconv.v_sprintf(sc1, a ,b ,c, d)
|
||||
sc1 := '==>%hhd %hd %d %ld'
|
||||
temp_s = strconv.v_sprintf(sc1, a, b, c, d)
|
||||
println(temp_s)
|
||||
```
|
||||
|
||||
@ -130,10 +131,10 @@ unsigned integer
|
||||
```v oksyntax
|
||||
a1 := byte(0xff)
|
||||
b1 := u16(0xffff)
|
||||
c1 := u32(0xffff_ffff)
|
||||
c1 := u32(0xffffffff)
|
||||
d1 := u64(-1)
|
||||
sc2 := "%hhu %hu %u %lu"
|
||||
temp_s = strconv.v_sprintf(sc2, a1 ,b1 ,c1, d1)
|
||||
sc2 := '%hhu %hu %u %lu'
|
||||
temp_s = strconv.v_sprintf(sc2, a1, b1, c1, d1)
|
||||
println(temp_s)
|
||||
```
|
||||
|
||||
@ -146,10 +147,10 @@ hexadecimal
|
||||
```v oksyntax
|
||||
a1 := byte(0xff)
|
||||
b1 := i16(0xffff)
|
||||
c1 := u32(0xffff_ffff)
|
||||
c1 := u32(0xffffffff)
|
||||
d1 := u64(-1)
|
||||
sc3 := "%hhx %hx %x %lx"
|
||||
temp_s = strconv.v_sprintf(sc3, a1 ,b1 ,c1, d1)
|
||||
sc3 := '%hhx %hx %x %lx'
|
||||
temp_s = strconv.v_sprintf(sc3, a1, b1, c1, d1)
|
||||
println(temp_s)
|
||||
```
|
||||
|
||||
@ -161,7 +162,7 @@ hexadecimal
|
||||
|
||||
```v oksyntax
|
||||
a2 := 125
|
||||
sc7 := "[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]"
|
||||
sc7 := '[%9x] [%9X] [%-9x] [%-9X] [%09x] [%09X]'
|
||||
temp_s = strconv.v_sprintf(sc7, a2, a2, a2, a2, a2, a2)
|
||||
println(temp_s)
|
||||
```
|
||||
@ -173,11 +174,11 @@ println(temp_s)
|
||||
floating points
|
||||
|
||||
```v oksyntax
|
||||
f0 := 0.312345
|
||||
f1 := 200000.0
|
||||
f2 := -1234.300e6
|
||||
f3 := 1234.300e-6
|
||||
sc4 := "[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]"
|
||||
f0 := 0.312345
|
||||
f1 := 200000.0
|
||||
f2 := -1234.300e6
|
||||
f3 := 1234.300e-6
|
||||
sc4 := '[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]'
|
||||
temp_s = strconv.v_sprintf(sc4, f0, f1, f1, f1, f2, f3)
|
||||
println(temp_s)
|
||||
```
|
||||
@ -190,11 +191,11 @@ float automatic notations
|
||||
|
||||
```v oksyntax
|
||||
mut ft := -1e-7
|
||||
mut x := 0
|
||||
sc8 := "[%20g][%20G]|"
|
||||
mut x := 0
|
||||
sc8 := '[%20g][%20G]|'
|
||||
for x < 12 {
|
||||
temp_s = strconv.v_sprintf(sc8, ft, ft)
|
||||
println("$temp_s\n")
|
||||
println('$temp_s\n')
|
||||
ft = ft * 10.0
|
||||
x++
|
||||
}
|
||||
@ -220,13 +221,13 @@ for x < 12 {
|
||||
|
||||
The format module also has some utility functions:
|
||||
|
||||
```v oksyntax
|
||||
```v oksyntax nofmt
|
||||
// calling struct
|
||||
struct BF_param {
|
||||
pad_ch byte = ` ` // padding char
|
||||
len0 int = -1 // default len for whole the number or string
|
||||
len1 int = 6 // number of decimal digits, if needed
|
||||
positive bool = true // mandatory: the sign of the number passed
|
||||
positive bool = true // mandatory: the sign of the number passed
|
||||
sign_flag bool = false // flag for print sign as prefix in padding
|
||||
allign Align_text = .right // alignment of the string
|
||||
rm_tail_zero bool = false // remove the tail zeros from floats
|
||||
@ -243,7 +244,7 @@ fn remove_tail_zeros(s string) string
|
||||
|
||||
`format_fl` format a float number in normal notation using the parameters in the `BF_param` struct.
|
||||
|
||||
`format_es format a float number in scientific notation using the parameters in the BF_param`
|
||||
`format_es format a float number in scientific notation using the parameters in the BF_param`
|
||||
struct.
|
||||
|
||||
`remove_tail_zeros` removes the tailing zeros from a floating point number as string.
|
||||
`remove_tail_zeros` removes the tailing zeros from a floating point number as string.
|
||||
|
@ -17,20 +17,20 @@ import term
|
||||
import os
|
||||
|
||||
fn main() {
|
||||
term.clear() // clears the content in the terminal
|
||||
width, height := term.get_terminal_size() // get the size of the terminal
|
||||
term.set_cursor_position(x: width / 2, y: height / 2) // now we point the cursor to the middle of the terminal
|
||||
println(term.strikethrough(term.bright_green("hello world"))) // Print green text
|
||||
term.set_cursor_position(x: 0, y: height) // Sets the position of the cursor to the bottom of the terminal
|
||||
mut var := os.input('press q to quit: ')
|
||||
// Keep prompting until the user presses the q key
|
||||
for {
|
||||
if var == 'q' {
|
||||
break
|
||||
} else {
|
||||
var = os.input('press q to quit: ')
|
||||
}
|
||||
}
|
||||
term.clear() // clears the content in the terminal
|
||||
width, height := term.get_terminal_size() // get the size of the terminal
|
||||
term.set_cursor_position(x: width / 2, y: height / 2) // now we point the cursor to the middle of the terminal
|
||||
println(term.strikethrough(term.bright_green('hello world'))) // Print green text
|
||||
term.set_cursor_position(x: 0, y: height) // Sets the position of the cursor to the bottom of the terminal
|
||||
mut var := os.input('press q to quit: ')
|
||||
// Keep prompting until the user presses the q key
|
||||
for {
|
||||
if var == 'q' {
|
||||
break
|
||||
} else {
|
||||
var = os.input('press q to quit: ')
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -42,55 +42,40 @@ Here are some functions you should be aware of in the `term `module:
|
||||
|
||||
```v oksyntax
|
||||
import term
|
||||
|
||||
// returns the height and the width of the terminal
|
||||
width, height := term.get_terminal_size()
|
||||
|
||||
// returns the string as green text to be printed on stdout
|
||||
term.ok_message('cool')
|
||||
|
||||
// returns the string as red text to be printed on stdout
|
||||
term.fail_message('oh, no')
|
||||
|
||||
// returns the string as yellow text to be printed on stdout
|
||||
term.warning_message('be warned')
|
||||
|
||||
//clears the entire terminal and leaves a blank one
|
||||
// clears the entire terminal and leaves a blank one
|
||||
term.clear()
|
||||
|
||||
// colors the output of the output, the available colors are: black,blue,yellow,green,cyan,gray,bright_blue,bright_green,bright_red,bright_black,bright_cyan
|
||||
term.yellow('submarine')
|
||||
|
||||
// transforms the given string into bold text
|
||||
term.bold('and beautiful')
|
||||
|
||||
// puts a strikethrough into the given string
|
||||
term.strikethrough('the core of the problem')
|
||||
|
||||
// underlines the given string
|
||||
term.underline('important')
|
||||
|
||||
// colors the background of the output following the given color
|
||||
// the available colors are: black, blue, yellow, green, cyan, gray
|
||||
term.bg_green('field')
|
||||
|
||||
// sets the position of the cursor at a given place in the terminal
|
||||
term.set_cursor_position(x: 5, y: 10)
|
||||
|
||||
// moves the cursor up
|
||||
term.cursor_up()
|
||||
|
||||
// moves the cursor down
|
||||
term.cursor_down()
|
||||
|
||||
// moves the cursor to the right
|
||||
term.cursor_forward()
|
||||
|
||||
// moves the cursor to the left
|
||||
term.cursor_back()
|
||||
|
||||
// shows the cursor
|
||||
term.show_cursor()
|
||||
|
||||
// hides the cursor
|
||||
term.hide_cursor()
|
||||
```
|
||||
|
@ -4,7 +4,7 @@ A V module for designing terminal UI apps
|
||||
|
||||
#### Quickstart
|
||||
|
||||
```v
|
||||
```v nofmt
|
||||
import term.ui as tui
|
||||
|
||||
struct App {
|
||||
|
@ -26,18 +26,23 @@ or `Preferences.compile_defines_all` **if any file is defined**.
|
||||
To parse something a new template is created as the first step:
|
||||
```v
|
||||
import v.table
|
||||
|
||||
table := table.new_table()
|
||||
```
|
||||
|
||||
a new preference is created:
|
||||
```v
|
||||
import v.pref
|
||||
|
||||
pref := pref.Preferences{}
|
||||
```
|
||||
|
||||
and a new scope is created:
|
||||
```v
|
||||
import v.ast
|
||||
|
||||
scope := ast.Scope{
|
||||
parent: 0
|
||||
parent: 0
|
||||
}
|
||||
```
|
||||
after that, you can parse your files.
|
||||
@ -46,6 +51,7 @@ after that, you can parse your files.
|
||||
If you want to parse only text which isn't saved on the disk you can use this function.
|
||||
```v oksyntax
|
||||
import v.parser
|
||||
|
||||
code := ''
|
||||
// table, pref and scope needs to be passed as reference
|
||||
parsed_file := parser.parse_text(code, table, .parse_comments, &pref, &scope)
|
||||
@ -56,6 +62,7 @@ For parsing files on disk, a path needs to be provided.
|
||||
The paths are collected one step earlier.
|
||||
```v oksyntax
|
||||
import v.parser
|
||||
|
||||
path := ''
|
||||
// table, pref and scope needs to be passed as reference
|
||||
parsed_file := parser.parse_file(path, table, .parse_comments, &pref, &scope)
|
||||
@ -66,6 +73,7 @@ If you have a batch of paths available which should be parsed,
|
||||
there is also a function which does all the work.
|
||||
```v oksyntax
|
||||
import v.parser
|
||||
|
||||
paths := ['']
|
||||
// table, pref and scope needs to be passed as reference
|
||||
parsed_files := parser.parse_files(paths, table, &pref, &scope)
|
||||
@ -86,6 +94,7 @@ Then all files from that directory are collected and parsed again like the previ
|
||||
A new checker is created:
|
||||
```v oksyntax
|
||||
import v.checker
|
||||
|
||||
mut checker := checker.new_checker(table, &pref)
|
||||
```
|
||||
|
||||
@ -105,5 +114,6 @@ checker.check_files(parsed_files)
|
||||
Generating C code works just as this:
|
||||
```v oksyntax
|
||||
import v.gen
|
||||
|
||||
res := gen.cgen(parsed_files, table, &pref)
|
||||
```
|
||||
|
@ -1,10 +1,10 @@
|
||||
> The name `json2` was chosen to avoid any unwanted potential conflicts with the
|
||||
> The name `json2` was chosen to avoid any unwanted potential conflicts with the
|
||||
> existing codegen tailored for the main `json` module which is powered by CJSON.
|
||||
|
||||
`x.json2` is an experimental JSON parser written from scratch on V.
|
||||
|
||||
## Usage
|
||||
```v oksyntax
|
||||
```v oksyntax nofmt
|
||||
import x.json2
|
||||
import net.http
|
||||
|
||||
@ -99,7 +99,7 @@ fn main() {
|
||||
```
|
||||
|
||||
## Using struct tags
|
||||
`x.json2` can access and use the struct field tags similar to the
|
||||
`x.json2` can access and use the struct field tags similar to the
|
||||
`json` module by using the comp-time `$for` for structs.
|
||||
|
||||
```v ignore
|
||||
@ -115,7 +115,7 @@ fn (mut p Person) from_json(f json2.Any) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
match field.name {
|
||||
'name' { p.name = mp[js_field_name].str() }
|
||||
'age' { u.age = mp[js_field_name].int() }
|
||||
@ -153,9 +153,9 @@ fn (mut p Person) from_json(f json2.Any) {
|
||||
|
||||
```v oksyntax
|
||||
fn (mut p Person) to_json() string {
|
||||
obj := f.as_map()
|
||||
obj['nickname'] = p.name
|
||||
return obj.str()
|
||||
obj := f.as_map()
|
||||
obj['nickname'] = p.name
|
||||
return obj.str()
|
||||
}
|
||||
```
|
||||
|
||||
@ -170,6 +170,6 @@ The following list shows the possible outputs when casting a value to an incompa
|
||||
|
||||
1. Casting non-array values as array (`arr()`) will return an array with the value as the content.
|
||||
2. Casting non-map values as map (`as_map()`) will return a map with the value as the content.
|
||||
3. Casting non-string values to string (`str()`) will return the
|
||||
3. Casting non-string values to string (`str()`) will return the
|
||||
JSON string representation of the value.
|
||||
4. Casting non-numeric values to int/float (`int()`/`i64()`/`f32()`/`f64()`) will return zero.
|
||||
|
Loading…
Reference in New Issue
Block a user