check-md: verify code example formatting (#7143)

pull/7152/head
Lukas Neubert 2020-12-05 22:54:41 +01:00 committed by GitHub
parent 0d28f12c54
commit 8adb1acf31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 836 additions and 752 deletions

View File

@ -24,7 +24,7 @@
## Key Features of V ## Key Features of V
- Simplicity: the language can be learned in less than an hour - 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)* ≈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 - 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) - Performance: as fast as C (V's main backend compiles to human readable C)
@ -81,7 +81,7 @@ v up
### C compiler ### 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. If you are doing development, you most likely already have one of those installed.
Otherwise, follow these instructions: 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) - [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, However, if none is found when running `make` on Linux or Windows,
TCC would be downloaded and set as an alternative C backend. TCC would be downloaded and set as an alternative C backend.
It's very lightweight (several MB) so this shouldn't take too long. It's very lightweight (several MB) so this shouldn't take too long.
### Symlinking ### Symlinking
@ -227,9 +227,9 @@ https://github.com/vlang/ui
```v ```v
fn main() { fn main() {
for i in 0..3 { for i in 0 .. 3 {
println('Hello from V.js') println('Hello from V.js')
} }
} }
``` ```

View File

@ -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')) return btext('$file_path:${lnumber + 1}:${column + 1}:') + btext(rtext(' error: $message'))
} }
//
const ( const (
default_command = 'compile' 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') vfile := os.join_path(os.temp_dir(), 'check_${fname}_example_${e.sline}__${e.eline}__${uid}.v')
mut should_cleanup_vfile := true mut should_cleanup_vfile := true
// eprintln('>>> checking example $vfile ...') // eprintln('>>> checking example $vfile ...')
vcontent := e.text.join('\n') vcontent := e.text.join('\n') + '\n'
os.write_file(vfile, vcontent) or { panic(err) } os.write_file(vfile, vcontent) or { panic(err) }
mut acommands := e.command.split(' ') mut acommands := e.command.split(' ')
nofmt := 'nofmt' in acommands
for command in acommands { for command in acommands {
match command { match command {
'compile' { 'compile' {
res := os.system('"$vexe" -w -Wfatal-errors -o x.c $vfile') res := os.system('"$vexe" -w -Wfatal-errors -o x.c $vfile')
os.rm('x.c') or { } os.rm('x.c') or { }
if res != 0 { fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') }
eprintln(eline(f.path, e.sline, 0, 'example failed to compile')) 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) eprintln(vcontent)
should_cleanup_vfile = false should_cleanup_vfile = false
errors++ errors++
@ -209,8 +215,14 @@ fn (mut f MDFile) check_examples() (int, int) {
} }
'live' { 'live' {
res := os.system('"$vexe" -w -Wfatal-errors -live -o x.c $vfile') res := os.system('"$vexe" -w -Wfatal-errors -live -o x.c $vfile')
if res != 0 { fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') }
eprintln(eline(f.path, e.sline, 0, 'example failed to compile with -live')) 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) eprintln(vcontent)
should_cleanup_vfile = false should_cleanup_vfile = false
errors++ errors++
@ -232,8 +244,14 @@ fn (mut f MDFile) check_examples() (int, int) {
} }
'oksyntax' { 'oksyntax' {
res := os.system('"$vexe" -w -Wfatal-errors -check-syntax $vfile') res := os.system('"$vexe" -w -Wfatal-errors -check-syntax $vfile')
if res != 0 { fmt_res := if nofmt { 0 } else { os.system('"$vexe" fmt -verify $vfile') }
eprintln(eline(f.path, e.sline, 0, '`oksyntax` example with invalid syntax')) 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) eprintln(vcontent)
should_cleanup_vfile = false should_cleanup_vfile = false
errors++ errors++
@ -252,6 +270,7 @@ fn (mut f MDFile) check_examples() (int, int) {
} }
oks++ oks++
} }
'nofmt' {}
else { else {
eprintln(eline(f.path, e.sline, 0, 'unrecognized command: "$command", use one of: wip/ignore/compile/failcompile/oksyntax/badsyntax')) eprintln(eline(f.path, e.sline, 0, 'unrecognized command: "$command", use one of: wip/ignore/compile/failcompile/oksyntax/badsyntax'))
should_cleanup_vfile = false should_cleanup_vfile = false

File diff suppressed because it is too large Load Diff

View File

@ -75,8 +75,11 @@ pub fn (mut app App) index() vweb.Result {
return vweb.Result{} return vweb.Result{}
} }
pub fn (app &App) init() {} pub fn (app &App) init() {
pub fn (app &App) init_once() {} }
pub fn (app &App) init_once() {
}
``` ```
Run it with Run it with
@ -103,6 +106,8 @@ no routing rules either:
```v oksyntax ```v oksyntax
import vweb import vweb
import time
fn (mut app App) time() vweb.Result { fn (mut app App) time() vweb.Result {
app.vweb.text(time.now().format()) app.vweb.text(time.now().format())
return vweb.Result{} return vweb.Result{}
@ -341,10 +346,11 @@ Create `new.html`:
```v oksyntax ```v oksyntax
import vweb import vweb
pub fn (mut app App) new_article() vweb.Result { pub fn (mut app App) new_article() vweb.Result {
title := app.vweb.form['title'] title := app.vweb.form['title']
text := app.vweb.form['text'] text := app.vweb.form['text']
if title == '' || text == '' { if title == '' || text == '' {
app.vweb.text('Empty text/title') app.vweb.text('Empty text/title')
return vweb.Result{} return vweb.Result{}
} }
@ -380,6 +386,8 @@ in V is very simple:
```v oksyntax ```v oksyntax
import vweb import vweb
import json
pub fn (mut app App) articles() vweb.Result { pub fn (mut app App) articles() vweb.Result {
articles := app.find_all_articles() articles := app.find_all_articles()
app.vweb.json(json.encode(articles)) app.vweb.json(json.encode(articles))

View File

@ -1,42 +1,43 @@
Example usage of this module: Example usage of this module:
``` ```v
import benchmark import benchmark
mut bmark := benchmark.new_benchmark() mut bmark := benchmark.new_benchmark()
// by default the benchmark will be verbose, i.e. it will include timing information // 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 // if you want it to be silent, set bmark.verbose = false
for { for {
bmark.step() // call this when you want to advance the benchmark. 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 // 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.fail() // call this if the step failed // bmark.step_message(('failed')
//bmark.step_message(('failed') bmark.ok() // call this when the step succeeded
println(bmark.step_message('ok'))
bmark.ok() // call this when the step succeeded
println( bmark.step_message('ok')
} }
bmark.stop() // call when you want to finalize the benchmark bmark.stop()
println( bmark.total_message('remarks about the benchmark') ) // call when you want to finalize the benchmark
println(bmark.total_message('remarks about the benchmark'))
``` ```
benchmark.start() and b.measure() are convenience methods, benchmark.start() and b.measure() are convenience methods,
intended to be used in combination. Their goal is to make intended to be used in combination. Their goal is to make
benchmarking of small snippets of code as *short*, easy to benchmarking of small snippets of code as *short*, easy to
write, and then to read and analyze the results, as possible. write, and then to read and analyze the results, as possible.
Example: Example:
```v ```v
import time import time
import benchmark import benchmark
mut b := benchmark.start()
mut b := benchmark.start()
// your code section 1 ... // your code section 1 ...
time.sleep_ms(1500) time.sleep_ms(1500)
b.measure('code_1') b.measure('code_1')
// your code section 2 ... // your code section 2 ...
time.sleep_ms(500) time.sleep_ms(500)
b.measure('code_2') b.measure('code_2')
``` ```
... which will produce on stdout something like this: ... which will produce on stdout something like this:
```text ```text
SPENT 1500.063 ms in code_1 SPENT 1500.063 ms in code_1

View File

@ -5,13 +5,13 @@ import encoding.csv
data := 'x,y\na,b,c\n' data := 'x,y\na,b,c\n'
mut parser := csv.new_reader(data) mut parser := csv.new_reader(data)
// read each line // read each line
for { for {
items := parser.read() or {break} items := parser.read() or { break }
println(items) println(items)
} }
``` ```
It prints: It prints:
``` ```
['x', 'y'] ['x', 'y']

View File

@ -35,20 +35,20 @@ fn cb(receiver voidptr, args voidptr, sender voidptr) {
// Since V can map structs to voidptr, this also works // Since V can map structs to voidptr, this also works
struct ClickEvent { struct ClickEvent {
x int x int
y int y int
} }
// Example case where publisher sends ClickEvent as args. // Example case where publisher sends ClickEvent as args.
fn on_press(receiver voidptr, e &ClickEvent, sender voidptr){ fn on_press(receiver voidptr, e &ClickEvent, sender voidptr) {
println(e.x) println(e.x)
//your code here... // your code here...
} }
``` ```
## Usage ## Usage
For **usage across modules** For **usage across modules**
[check the example](https://github.com/vlang/v/tree/master/examples/eventbus). [check the example](https://github.com/vlang/v/tree/master/examples/eventbus).
_Note: As a general rule, you will need to **subscribe before publishing**._ _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 ```v oksyntax
module main module main
import eventbus import eventbus
// initialize it globally // initialize it globally
const ( const (
eb = eventbus.new() eb = eventbus.new()
) )
fn main(){ fn main() {
// get a mutable reference to the subscriber // get a mutable reference to the subscriber
mut sub := eb.subscriber mut sub := eb.subscriber
// subscribe to the 'error' event // subscribe to the 'error' event
sub.subscribe("error", on_error) sub.subscribe('error', on_error)
// start the work // start the work
do_work() do_work()
} }
// the event handler // the event handler
fn on_error(receiver voidptr, e &Error, work &Work) { 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 ```v oksyntax
module main module main
struct Work{ struct Work {
hours int hours int
} }
struct Error { struct Error {
message string message string
} }
fn do_work(){ fn do_work() {
work := Work{20} work := Work{20}
// get a mutable Params instance & put some data into it // get a mutable Params instance & put some data into it
error := &Error{"Error: no internet connection."} error := &Error{'Error: no internet connection.'}
// publish the event // publish the event
eb.publish("error", work, error) eb.publish('error', work, error)
} }
``` ```

View File

@ -160,20 +160,17 @@ that is an `[]int` inside the `RE` struct.
**example:** **example:**
```v oksyntax ```v oksyntax
text := "cpaz cpapaz cpapapaz" text := 'cpaz cpapaz cpapapaz'
query:= r"(c(pa)+z ?)+" query := r'(c(pa)+z ?)+'
mut re := regex.regex_opt(query) or { panic(err) } mut re := regex.regex_opt(query) or { panic(err) }
println(re.get_query()) 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 // #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, end := re.match_string(text)
// [start=0, end=20] match => [cpaz cpapaz cpapapaz] // [start=0, end=20] match => [cpaz cpapaz cpapapaz]
mut gi := 0 mut gi := 0
for gi < re.groups.len { for gi < re.groups.len {
if re.groups[gi] >= 0 { 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 gi += 2
} }
@ -260,45 +257,42 @@ If the space ends no error is raised, further records will not be saved.
```v oksyntax ```v oksyntax
fn example2() { fn example2() {
test_regex() test_regex()
text := 'tst: 01,23,45 ,56, 78'
text := "tst: 01,23,45 ,56, 78" query := r'.*:(\s*\d+[\s,]*)+'
query:= r".*:(\s*\d+[\s,]*)+"
mut re := new() or { panic(err) } mut re := new() or { panic(err) }
//re.debug = 2 // re.debug = 2
re.group_csave = [-1].repeat(3*20+1) // we expect max 20 records re.group_csave = [-1].repeat(3 * 20 + 1) // we expect max 20 records
re.compile_opt(query) or {
re.compile_opt(query) or { println(err) return } println(err)
return
q_str := re.get_query() }
println("Query: $q_str") q_str := re.get_query()
println('Query: $q_str')
start, end := re.match_string(text) start, end := re.match_string(text)
if start < 0 { if start < 0 {
println("ERROR : ${re.get_parse_error_string(start)}, $start") println('ERROR : ${re.get_parse_error_string(start)}, $start')
} else { } else {
println("found in [$start, $end] => [${text[start..end]}]") println('found in [$start, $end] => [${text[start..end]}]')
} }
// groups capture
// groups capture mut gi := 0
mut gi := 0 for gi < re.groups.len {
for gi < re.groups.len { if re.groups[gi] >= 0 {
if re.groups[gi] >= 0 { println('${gi / 2} ${re.groups[gi]},${re.groups[gi + 1]} :[${text[re.groups[gi]..re.groups[gi +
println("${gi/2} ${re.groups[gi]},${re.groups[gi+1]} :[${text[re.groups[gi]..re.groups[gi+1]]}]") 1]]}]')
} }
gi += 2 gi += 2
} }
// continuous saving
// continuous saving gi = 0
gi = 0 println('num: ${re.group_csave[0]}')
println("num: ${re.group_csave[0]}") for gi < re.group_csave[0] {
for gi < re.group_csave[0] { id := re.group_csave[1 + gi * 3]
id := re.group_csave[1+gi*3] st := re.group_csave[1 + gi * 3 + 1]
st := re.group_csave[1+gi*3+1] en := re.group_csave[1 + gi * 3 + 2]
en := re.group_csave[1+gi*3+2] println('cg id: $id [$st, $en] => [${text[st..en]}]')
println("cg id: ${id} [${st}, ${en}] => [${text[st..en]}]") gi++
gi++ }
}
} }
``` ```
@ -333,64 +327,61 @@ example:
```v ignore ```v ignore
import regex import regex
fn main() { fn main() {
test_regex() test_regex()
text := 'http://www.ciao.mondo/hello/pippo12_/pera.html'
text := "http://www.ciao.mondo/hello/pippo12_/pera.html" query := r'(?P<format>https?)|(?:ftps?)://(?P<token>[\w_]+.)+'
query:= r"(?P<format>https?)|(?:ftps?)://(?P<token>[\w_]+.)+"
mut re := new() mut re := new()
re.debug = 2 re.debug = 2
// must provide an array of the right size if want the continuos saving of the groups // 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.group_csave = [-1].repeat(3 * 20 + 1)
re.compile_opt(query) or {
re.compile_opt(query) or { println(err) return } println(err)
return
q_str := re.get_query() }
println("O.Query: $query") q_str := re.get_query()
println("Query : $q_str") println('O.Query: $query')
println('Query : $q_str')
re.debug = 0 re.debug = 0
start, end := re.match_string(text) start, end := re.match_string(text)
if start < 0 { if start < 0 {
err_str := re.get_parse_error_string(start) err_str := re.get_parse_error_string(start)
println("ERROR : $err_str, $start") println('ERROR : $err_str, $start')
} else { } else {
text1 := text[start..end] text1 := text[start..end]
println("found in [$start, $end] => [$text1]") println('found in [$start, $end] => [$text1]')
} }
// groups
// groups mut gi := 0
mut gi := 0 for gi < re.groups.len {
for gi < re.groups.len { if re.groups[gi] >= 0 {
if re.groups[gi] >= 0 { println('${gi / 2} ${re.groups[gi]},${re.groups[gi + 1]} :[${text[re.groups[gi]..re.groups[gi +
println("${gi/2} ${re.groups[gi]},${re.groups[gi+1]} :[${text[re.groups[gi]..re.groups[gi+1]]}]") 1]]}]')
} }
gi += 2 gi += 2
} }
// continuous saving // continuous saving
gi = 0 gi = 0
println("num of group item saved: ${re.group_csave[0]}") println('num of group item saved: ${re.group_csave[0]}')
for gi < re.group_csave[0] { for gi < re.group_csave[0] {
id := re.group_csave[1+gi*3] id := re.group_csave[1 + gi * 3]
st := re.group_csave[1+gi*3+1] st := re.group_csave[1 + gi * 3 + 1]
en := re.group_csave[1+gi*3+2] en := re.group_csave[1 + gi * 3 + 2]
println("cg id: ${id} [${st}, ${en}] => [${text[st..en]}]") println('cg id: $id [$st, $en] => [${text[st..en]}]')
gi++ gi++
} }
println("raw array: ${re.group_csave[0..gi*3+2-1]}") println('raw array: ${re.group_csave[0..gi * 3 + 2 - 1]}')
// named capturing groups
// named capturing groups println('named capturing groups:')
println("named capturing groups:") for g_name in re.group_map.keys() {
for g_name in re.group_map.keys() { s, e := re.get_group(g_name)
s,e := re.get_group(g_name) if s >= 0 && e > s {
if s >= 0 && e > s { println("'$g_name':[$s, $e] => '${text[s..e]}'")
println("'${g_name}':[$s, $e] => '${text[s..e]}'") } else {
} else { println("Group [$g_name] doesn't exist.")
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: the following example code show how to visualize the syntax errors in the compilation phase:
```v oksyntax ```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() mut re := new()
re.compile_opt(query) or { println(err) } re.compile_opt(query) or { println(err) }
// output!! // output!!
// query: ciao da ab[ab-]
//query: ciao da ab[ab-] // err : ----------^
//err : ----------^ // ERROR: ERR_SYNTAX_ERROR
//ERROR: ERR_SYNTAX_ERROR
``` ```
### **Compiled code** ### **Compiled code**
@ -636,12 +624,12 @@ it is possible to provide an alternative output setting a custom output functio
```v oksyntax ```v oksyntax
// custom print function, the input will be the regex debug string // custom print function, the input will be the regex debug string
fn custom_print(txt string) { fn custom_print(txt string) {
println("my log: $txt") println('my log: $txt')
} }
mut re := new() 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 ## Example code
@ -652,44 +640,45 @@ Here there is a simple code to perform some basically match of strings
struct TestObj { struct TestObj {
source string // source string to parse source string // source string to parse
query string // regex query string query string // regex query string
s int // expected match start index s int // expected match start index
e int // expected match end index e int // expected match end index
} }
const ( const (
tests = [ tests = [
TestObj{"this is a good.",r"this (\w+) a",0,9}, TestObj{'this is a good.', r'this (\w+) a', 0, 9},
TestObj{"this,these,those. over",r"(th[eio]se?[,. ])+",0,17}, TestObj{'this,these,those. over', r'(th[eio]se?[,. ])+', 0, 17},
TestObj{"test1@post.pip.com, pera",r"[\w]+@([\w]+\.)+\w+",0,18}, TestObj{'test1@post.pip.com, pera', r'[\w]+@([\w]+\.)+\w+', 0, 18},
TestObj{"cpapaz ole. pippo,",r".*c.+ole.*pi",0,14}, TestObj{'cpapaz ole. pippo,', r'.*c.+ole.*pi', 0, 14},
TestObj{"adce aabe",r"(a(ab)+)|(a(dc)+)e",0,4}, TestObj{'adce aabe', r'(a(ab)+)|(a(dc)+)e', 0, 4},
] ]
) )
fn example() { fn example() {
for c,tst in tests { for c, tst in tests {
mut re := regex.new() mut re := regex.new()
re.compile_opt(tst.query) or { println(err) continue } re.compile_opt(tst.query) or {
println(err)
// print the query parsed with the groups ids continue
re.debug = 1 // set debug on at minimum level }
println("#${c:2d} query parsed: ${re.get_query()}") // print the query parsed with the groups ids
re.debug = 0 re.debug = 1 // set debug on at minimum level
println('#${c:2d} query parsed: $re.get_query()')
// do the match re.debug = 0
start, end := re.match_string(tst.source) // do the match
if start >= 0 && end > start { start, end := re.match_string(tst.source)
println("#${c:2d} found in: [$start, $end] => [${tst.source[start..end]}]") if start >= 0 && end > start {
} println('#${c:2d} found in: [$start, $end] => [${tst.source[start..end]}]')
}
// print the groups // print the groups
mut gi := 0 mut gi := 0
for gi < re.groups.len { for gi < re.groups.len {
if re.groups[gi] >= 0 { if re.groups[gi] >= 0 {
println("group ${gi/2:2d} :[${tst.source[re.groups[gi]..re.groups[gi+1]]}]") println('group ${gi / 2:2d} :[${tst.source[re.groups[gi]..re.groups[gi + 1]]}]')
} }
gi += 2 gi += 2
} }
println("") println('')
} }
} }

View File

@ -8,20 +8,19 @@ A library for working with versions in [semver][semver] format.
import semver import semver
fn main() { fn main() {
ver1 := semver.from('1.2.4') or { ver1 := semver.from('1.2.4') or {
println('Invalid version') println('Invalid version')
return return
} }
ver2 := semver.from('2.3.4') or { ver2 := semver.from('2.3.4') or {
println('Invalid version') println('Invalid version')
return return
} }
println(ver1.gt(ver2))
println(ver1.gt(ver2)) println(ver2.gt(ver1))
println(ver2.gt(ver1)) println(ver1.satisfies('>=1.1.0 <2.0.0'))
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')) println(ver2.satisfies('>=1.1.0 <2.0.0 || >2.2.0'))
println(ver2.satisfies('>=1.1.0 <2.0.0 || >2.2.0'))
} }
``` ```

View File

@ -13,9 +13,10 @@ is replaced by the textual version of the following parameters.
```v ```v
import strconv import strconv
fn main() { fn main() {
a := "World" a := 'World'
s := strconv.v_sprintf("Hello %s!", a) s := strconv.v_sprintf('Hello %s!', a)
println(s) println(s)
} }
``` ```
@ -49,16 +50,16 @@ The Flags field may be zero or more (in any order) of:
#### Width field #### Width field
The Width field specifies a *maximum* number of characters to output, The Width field specifies a *maximum* number of characters to output,
and is typically used to pad fixed-width fields in tabulated output, and is typically used to pad fixed-width fields in tabulated output,
it causes truncation of oversized fields. it causes truncation of oversized fields.
The width field may be omitted, or it may be a numeric integer value, 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 `*`. 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, For example, `v_printf("%*.s", 5, my_string)` will result in ` mystring` being printed,
with a total width of 5 characters. with a total width of 5 characters.
#### Length field #### Length field
The Length field can be omitted or be any of: 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: The Type field can be any of:
@ -93,15 +94,15 @@ The Type field can be any of:
various types various types
```v oksyntax ```v oksyntax
a0 := u32(10) a0 := u32(10)
b0 := 200 b0 := 200
c0 := byte(12) c0 := byte(12)
s0 := "ciAo" s0 := 'ciAo'
ch0 := `B` ch0 := `B`
f0 := 0.312345 f0 := 0.312345
f1 := 200000.0 f1 := 200000.0
sc0 := "ciao: [%-08u] %d %hhd [%8s] [%08X] [%-20.4f] [%-20.4f] [%c]" 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) temp_s = strconv.v_sprintf(sc0, a0, b0, c0, s0, b0, f0, f1, ch0)
println(temp_s) println(temp_s)
``` ```
@ -116,8 +117,8 @@ a := byte(12)
b := i16(13) b := i16(13)
c := 14 c := 14
d := i64(15) d := i64(15)
sc1 := "==>%hhd %hd %d %ld" sc1 := '==>%hhd %hd %d %ld'
temp_s = strconv.v_sprintf(sc1, a ,b ,c, d) temp_s = strconv.v_sprintf(sc1, a, b, c, d)
println(temp_s) println(temp_s)
``` ```
@ -130,10 +131,10 @@ unsigned integer
```v oksyntax ```v oksyntax
a1 := byte(0xff) a1 := byte(0xff)
b1 := u16(0xffff) b1 := u16(0xffff)
c1 := u32(0xffff_ffff) c1 := u32(0xffffffff)
d1 := u64(-1) d1 := u64(-1)
sc2 := "%hhu %hu %u %lu" sc2 := '%hhu %hu %u %lu'
temp_s = strconv.v_sprintf(sc2, a1 ,b1 ,c1, d1) temp_s = strconv.v_sprintf(sc2, a1, b1, c1, d1)
println(temp_s) println(temp_s)
``` ```
@ -146,10 +147,10 @@ hexadecimal
```v oksyntax ```v oksyntax
a1 := byte(0xff) a1 := byte(0xff)
b1 := i16(0xffff) b1 := i16(0xffff)
c1 := u32(0xffff_ffff) c1 := u32(0xffffffff)
d1 := u64(-1) d1 := u64(-1)
sc3 := "%hhx %hx %x %lx" sc3 := '%hhx %hx %x %lx'
temp_s = strconv.v_sprintf(sc3, a1 ,b1 ,c1, d1) temp_s = strconv.v_sprintf(sc3, a1, b1, c1, d1)
println(temp_s) println(temp_s)
``` ```
@ -161,7 +162,7 @@ hexadecimal
```v oksyntax ```v oksyntax
a2 := 125 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) temp_s = strconv.v_sprintf(sc7, a2, a2, a2, a2, a2, a2)
println(temp_s) println(temp_s)
``` ```
@ -173,11 +174,11 @@ println(temp_s)
floating points floating points
```v oksyntax ```v oksyntax
f0 := 0.312345 f0 := 0.312345
f1 := 200000.0 f1 := 200000.0
f2 := -1234.300e6 f2 := -1234.300e6
f3 := 1234.300e-6 f3 := 1234.300e-6
sc4 := "[%-20.3e] [%20.3e] [%-020.3e] [%-020.3E] [%-020.3e] [%-020.3e]" 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) temp_s = strconv.v_sprintf(sc4, f0, f1, f1, f1, f2, f3)
println(temp_s) println(temp_s)
``` ```
@ -190,11 +191,11 @@ float automatic notations
```v oksyntax ```v oksyntax
mut ft := -1e-7 mut ft := -1e-7
mut x := 0 mut x := 0
sc8 := "[%20g][%20G]|" sc8 := '[%20g][%20G]|'
for x < 12 { for x < 12 {
temp_s = strconv.v_sprintf(sc8, ft, ft) temp_s = strconv.v_sprintf(sc8, ft, ft)
println("$temp_s\n") println('$temp_s\n')
ft = ft * 10.0 ft = ft * 10.0
x++ x++
} }
@ -220,13 +221,13 @@ for x < 12 {
The format module also has some utility functions: The format module also has some utility functions:
```v oksyntax ```v oksyntax nofmt
// calling struct // calling struct
struct BF_param { struct BF_param {
pad_ch byte = ` ` // padding char pad_ch byte = ` ` // padding char
len0 int = -1 // default len for whole the number or string len0 int = -1 // default len for whole the number or string
len1 int = 6 // number of decimal digits, if needed 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 sign_flag bool = false // flag for print sign as prefix in padding
allign Align_text = .right // alignment of the string allign Align_text = .right // alignment of the string
rm_tail_zero bool = false // remove the tail zeros from floats 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_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. 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.

View File

@ -17,20 +17,20 @@ import term
import os import os
fn main() { fn main() {
term.clear() // clears the content in the terminal term.clear() // clears the content in the terminal
width, height := term.get_terminal_size() // get the size of 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 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 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 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: ') mut var := os.input('press q to quit: ')
// Keep prompting until the user presses the q key // Keep prompting until the user presses the q key
for { for {
if var == 'q' { if var == 'q' {
break break
} else { } else {
var = os.input('press q to quit: ') 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 ```v oksyntax
import term import term
// returns the height and the width of the terminal // returns the height and the width of the terminal
width, height := term.get_terminal_size() width, height := term.get_terminal_size()
// returns the string as green text to be printed on stdout // returns the string as green text to be printed on stdout
term.ok_message('cool') term.ok_message('cool')
// returns the string as red text to be printed on stdout // returns the string as red text to be printed on stdout
term.fail_message('oh, no') term.fail_message('oh, no')
// returns the string as yellow text to be printed on stdout // returns the string as yellow text to be printed on stdout
term.warning_message('be warned') 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() 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 // 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') term.yellow('submarine')
// transforms the given string into bold text // transforms the given string into bold text
term.bold('and beautiful') term.bold('and beautiful')
// puts a strikethrough into the given string // puts a strikethrough into the given string
term.strikethrough('the core of the problem') term.strikethrough('the core of the problem')
// underlines the given string // underlines the given string
term.underline('important') term.underline('important')
// colors the background of the output following the given color // colors the background of the output following the given color
// the available colors are: black, blue, yellow, green, cyan, gray // the available colors are: black, blue, yellow, green, cyan, gray
term.bg_green('field') term.bg_green('field')
// sets the position of the cursor at a given place in the terminal // sets the position of the cursor at a given place in the terminal
term.set_cursor_position(x: 5, y: 10) term.set_cursor_position(x: 5, y: 10)
// moves the cursor up // moves the cursor up
term.cursor_up() term.cursor_up()
// moves the cursor down // moves the cursor down
term.cursor_down() term.cursor_down()
// moves the cursor to the right // moves the cursor to the right
term.cursor_forward() term.cursor_forward()
// moves the cursor to the left // moves the cursor to the left
term.cursor_back() term.cursor_back()
// shows the cursor // shows the cursor
term.show_cursor() term.show_cursor()
// hides the cursor // hides the cursor
term.hide_cursor() term.hide_cursor()
``` ```

View File

@ -4,7 +4,7 @@ A V module for designing terminal UI apps
#### Quickstart #### Quickstart
```v ```v nofmt
import term.ui as tui import term.ui as tui
struct App { struct App {

View File

@ -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: To parse something a new template is created as the first step:
```v ```v
import v.table import v.table
table := table.new_table() table := table.new_table()
``` ```
a new preference is created: a new preference is created:
```v ```v
import v.pref import v.pref
pref := pref.Preferences{} pref := pref.Preferences{}
``` ```
and a new scope is created: and a new scope is created:
```v ```v
import v.ast import v.ast
scope := ast.Scope{ scope := ast.Scope{
parent: 0 parent: 0
} }
``` ```
after that, you can parse your files. 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. If you want to parse only text which isn't saved on the disk you can use this function.
```v oksyntax ```v oksyntax
import v.parser import v.parser
code := '' code := ''
// table, pref and scope needs to be passed as reference // table, pref and scope needs to be passed as reference
parsed_file := parser.parse_text(code, table, .parse_comments, &pref, &scope) 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. The paths are collected one step earlier.
```v oksyntax ```v oksyntax
import v.parser import v.parser
path := '' path := ''
// table, pref and scope needs to be passed as reference // table, pref and scope needs to be passed as reference
parsed_file := parser.parse_file(path, table, .parse_comments, &pref, &scope) 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. there is also a function which does all the work.
```v oksyntax ```v oksyntax
import v.parser import v.parser
paths := [''] paths := ['']
// table, pref and scope needs to be passed as reference // table, pref and scope needs to be passed as reference
parsed_files := parser.parse_files(paths, table, &pref, &scope) 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: A new checker is created:
```v oksyntax ```v oksyntax
import v.checker import v.checker
mut checker := checker.new_checker(table, &pref) mut checker := checker.new_checker(table, &pref)
``` ```
@ -105,5 +114,6 @@ checker.check_files(parsed_files)
Generating C code works just as this: Generating C code works just as this:
```v oksyntax ```v oksyntax
import v.gen import v.gen
res := gen.cgen(parsed_files, table, &pref) res := gen.cgen(parsed_files, table, &pref)
``` ```

View File

@ -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. > 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. `x.json2` is an experimental JSON parser written from scratch on V.
## Usage ## Usage
```v oksyntax ```v oksyntax nofmt
import x.json2 import x.json2
import net.http import net.http
@ -99,7 +99,7 @@ fn main() {
``` ```
## Using struct tags ## 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. `json` module by using the comp-time `$for` for structs.
```v ignore ```v ignore
@ -115,7 +115,7 @@ fn (mut p Person) from_json(f json2.Any) {
break break
} }
} }
match field.name { match field.name {
'name' { p.name = mp[js_field_name].str() } 'name' { p.name = mp[js_field_name].str() }
'age' { u.age = mp[js_field_name].int() } 'age' { u.age = mp[js_field_name].int() }
@ -153,9 +153,9 @@ fn (mut p Person) from_json(f json2.Any) {
```v oksyntax ```v oksyntax
fn (mut p Person) to_json() string { fn (mut p Person) to_json() string {
obj := f.as_map() obj := f.as_map()
obj['nickname'] = p.name obj['nickname'] = p.name
return obj.str() 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. 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. 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. JSON string representation of the value.
4. Casting non-numeric values to int/float (`int()`/`i64()`/`f32()`/`f64()`) will return zero. 4. Casting non-numeric values to int/float (`int()`/`i64()`/`f32()`/`f64()`) will return zero.