Compare commits
34 Commits
9d764cd25e
...
b81f06e369
| Author | SHA1 | Date |
|---|---|---|
|
|
b81f06e369 | |
|
|
1cc8072efa | |
|
|
2d381d69ea | |
|
|
549735fbff | |
|
|
d67251c1e0 | |
|
|
8a5ba0dfc8 | |
|
|
b314b8d8bf | |
|
|
81963b51ab | |
|
|
b43c538bc0 | |
|
|
13902a827b | |
|
|
5b58f4efbf | |
|
|
47e7582af8 | |
|
|
b849651197 | |
|
|
2134fb3e3e | |
|
|
cde15abc0a | |
|
|
745e75ab25 | |
|
|
6690dfa208 | |
|
|
f3dff7c1c0 | |
|
|
20ded157bf | |
|
|
1f471a4628 | |
|
|
0b7c3a6035 | |
|
|
0a30a90924 | |
|
|
7325727e38 | |
|
|
e0963381ec | |
|
|
2c59d47fc1 | |
|
|
08f45023e8 | |
|
|
a7e8ca70dc | |
|
|
6eea50c955 | |
|
|
34961a23b4 | |
|
|
dc9068b4d3 | |
|
|
052c8e0282 | |
|
|
0a12fd7212 | |
|
|
eca95dcedc | |
|
|
8824f5f103 |
|
|
@ -61,9 +61,7 @@ fn main() {
|
|||
if term_colors {
|
||||
os.setenv('VCOLORS', 'always', true)
|
||||
}
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt foptions: $foptions')
|
||||
}
|
||||
foptions.vlog('vfmt foptions: $foptions')
|
||||
if foptions.is_worker {
|
||||
// -worker should be added by a parent vfmt process.
|
||||
// We launch a sub process for each file because
|
||||
|
|
@ -109,9 +107,7 @@ fn main() {
|
|||
mut worker_command_array := cli_args_no_files.clone()
|
||||
worker_command_array << ['-worker', util.quote_path(fpath)]
|
||||
worker_cmd := worker_command_array.join(' ')
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt worker_cmd: $worker_cmd')
|
||||
}
|
||||
foptions.vlog('vfmt worker_cmd: $worker_cmd')
|
||||
worker_result := os.execute(worker_cmd)
|
||||
// Guard against a possibly crashing worker process.
|
||||
if worker_result.exit_code != 0 {
|
||||
|
|
@ -151,43 +147,43 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
fn (foptions &FormatOptions) format_file(file string) {
|
||||
fn setup_preferences_and_table() (&pref.Preferences, &ast.Table) {
|
||||
table := ast.new_table()
|
||||
mut prefs := pref.new_preferences()
|
||||
prefs.is_fmt = true
|
||||
prefs.skip_warnings = true
|
||||
return prefs, table
|
||||
}
|
||||
|
||||
fn (foptions &FormatOptions) vlog(msg string) {
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt2 running fmt.fmt over file: $file')
|
||||
eprintln(msg)
|
||||
}
|
||||
table := ast.new_table()
|
||||
// checker := checker.new_checker(table, prefs)
|
||||
}
|
||||
|
||||
fn (foptions &FormatOptions) format_file(file string) {
|
||||
foptions.vlog('vfmt2 running fmt.fmt over file: $file')
|
||||
prefs, table := setup_preferences_and_table()
|
||||
file_ast := parser.parse_file(file, table, .parse_comments, prefs)
|
||||
// checker.check(file_ast)
|
||||
// checker.new_checker(table, prefs).check(file_ast)
|
||||
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
|
||||
file_name := os.file_name(file)
|
||||
ulid := rand.ulid()
|
||||
vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name')
|
||||
os.write_file(vfmt_output_path, formatted_content) or { panic(err) }
|
||||
if foptions.is_verbose {
|
||||
eprintln('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .')
|
||||
}
|
||||
foptions.vlog('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .')
|
||||
eprintln('$formatted_file_token$vfmt_output_path')
|
||||
}
|
||||
|
||||
fn (foptions &FormatOptions) format_pipe() {
|
||||
mut prefs := pref.new_preferences()
|
||||
prefs.is_fmt = true
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt2 running fmt.fmt over stdin')
|
||||
}
|
||||
foptions.vlog('vfmt2 running fmt.fmt over stdin')
|
||||
prefs, table := setup_preferences_and_table()
|
||||
input_text := os.get_raw_lines_joined()
|
||||
table := ast.new_table()
|
||||
// checker := checker.new_checker(table, prefs)
|
||||
file_ast := parser.parse_text(input_text, '', table, .parse_comments, prefs)
|
||||
// checker.check(file_ast)
|
||||
// checker.new_checker(table, prefs).check(file_ast)
|
||||
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
|
||||
print(formatted_content)
|
||||
if foptions.is_verbose {
|
||||
eprintln('fmt.fmt worked and $formatted_content.len bytes were written to stdout.')
|
||||
}
|
||||
foptions.vlog('fmt.fmt worked and $formatted_content.len bytes were written to stdout.')
|
||||
}
|
||||
|
||||
fn print_compiler_options(compiler_params &pref.Preferences) {
|
||||
|
|
@ -234,9 +230,7 @@ fn (mut foptions FormatOptions) post_process_file(file string, formatted_file_pa
|
|||
return
|
||||
}
|
||||
diff_cmd := foptions.find_diff_cmd()
|
||||
if foptions.is_verbose {
|
||||
eprintln('Using diff command: $diff_cmd')
|
||||
}
|
||||
foptions.vlog('Using diff command: $diff_cmd')
|
||||
diff := diff.color_compare_files(diff_cmd, file, formatted_file_path)
|
||||
if diff.len > 0 {
|
||||
println(diff)
|
||||
|
|
|
|||
|
|
@ -49,17 +49,26 @@ enum RunCommandKind {
|
|||
|
||||
const expect_nothing = '<nothing>'
|
||||
|
||||
const starts_with_nothing = '<nothing>'
|
||||
|
||||
const ends_with_nothing = '<nothing>'
|
||||
|
||||
const contains_nothing = '<nothing>'
|
||||
|
||||
struct Command {
|
||||
mut:
|
||||
line string
|
||||
label string // when set, the label will be printed *before* cmd.line is executed
|
||||
ecode int
|
||||
okmsg string
|
||||
errmsg string
|
||||
rmfile string
|
||||
runcmd RunCommandKind = .system
|
||||
expect string = expect_nothing
|
||||
output string
|
||||
line string
|
||||
label string // when set, the label will be printed *before* cmd.line is executed
|
||||
ecode int
|
||||
okmsg string
|
||||
errmsg string
|
||||
rmfile string
|
||||
runcmd RunCommandKind = .system
|
||||
expect string = expect_nothing
|
||||
starts_with string = starts_with_nothing
|
||||
ends_with string = ends_with_nothing
|
||||
contains string = contains_nothing
|
||||
output string
|
||||
}
|
||||
|
||||
fn get_all_commands() []Command {
|
||||
|
|
@ -99,6 +108,14 @@ fn get_all_commands() []Command {
|
|||
runcmd: .execute
|
||||
expect: 'Hello, World!\n'
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe interpret examples/hanoi.v'
|
||||
okmsg: 'V can interpret hanoi.v'
|
||||
runcmd: .execute
|
||||
starts_with: 'Disc 1 from A to C...\n'
|
||||
ends_with: 'Disc 1 from A to C...\n'
|
||||
contains: 'Disc 7 from A to C...\n'
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe -o - examples/hello_world.v | grep "#define V_COMMIT_HASH" > /dev/null'
|
||||
okmsg: 'V prints the generated source code to stdout with `-o -` .'
|
||||
|
|
@ -252,23 +269,56 @@ fn (mut cmd Command) run() {
|
|||
spent := sw.elapsed().milliseconds()
|
||||
//
|
||||
mut is_failed := false
|
||||
mut is_failed_expected := false
|
||||
mut is_failed_starts_with := false
|
||||
mut is_failed_ends_with := false
|
||||
mut is_failed_contains := false
|
||||
if cmd.ecode != 0 {
|
||||
is_failed = true
|
||||
}
|
||||
if cmd.expect != expect_nothing {
|
||||
if cmd.output != cmd.expect {
|
||||
is_failed = true
|
||||
is_failed_expected = true
|
||||
}
|
||||
}
|
||||
if cmd.starts_with != starts_with_nothing {
|
||||
if !cmd.output.starts_with(cmd.starts_with) {
|
||||
is_failed = true
|
||||
is_failed_starts_with = true
|
||||
}
|
||||
}
|
||||
if cmd.ends_with != ends_with_nothing {
|
||||
if !cmd.output.ends_with(cmd.ends_with) {
|
||||
is_failed = true
|
||||
is_failed_ends_with = true
|
||||
}
|
||||
}
|
||||
if cmd.contains != contains_nothing {
|
||||
if !cmd.output.contains(cmd.contains) {
|
||||
is_failed = true
|
||||
is_failed_contains = true
|
||||
}
|
||||
}
|
||||
//
|
||||
run_label := if is_failed { term.failed('FAILED') } else { term_highlight('OK') }
|
||||
println('> Running: "$cmd.line" took: $spent ms ... $run_label')
|
||||
//
|
||||
if is_failed && cmd.expect != expect_nothing {
|
||||
if cmd.output != cmd.expect {
|
||||
eprintln('> expected:\n$cmd.expect')
|
||||
eprintln('> output:\n$cmd.output')
|
||||
}
|
||||
if is_failed && is_failed_expected {
|
||||
eprintln('> expected:\n$cmd.expect')
|
||||
eprintln('> output:\n$cmd.output')
|
||||
}
|
||||
if is_failed && is_failed_starts_with {
|
||||
eprintln('> expected to start with:\n$cmd.starts_with')
|
||||
eprintln('> output:\n${cmd.output#[..cmd.starts_with.len]}')
|
||||
}
|
||||
if is_failed && is_failed_ends_with {
|
||||
eprintln('> expected to end with:\n$cmd.ends_with')
|
||||
eprintln('> output:\n${cmd.output#[-cmd.starts_with.len..]}')
|
||||
}
|
||||
if is_failed && is_failed_contains {
|
||||
eprintln('> expected to contain:\n$cmd.contains')
|
||||
eprintln('> output:\n$cmd.output')
|
||||
}
|
||||
if vtest_nocleanup {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ const (
|
|||
|
||||
struct App {
|
||||
minutes_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw,
|
||||
tp +
|
||||
1 * th, center - tw, tp + 1 * th]
|
||||
tp + 1 * th, center - tw, tp + 1 * th]
|
||||
hours_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw, tp + 2 * th,
|
||||
center - tw, tp + 2 * th]
|
||||
hours3_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw, tp + 3 * th,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
fn main() {
|
||||
graph := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
println('Graph: $graph')
|
||||
path := breadth_first_search_path(graph, 'A', 'F')
|
||||
println('The shortest path from node A to node F is: $path')
|
||||
assert path == ['A', 'C', 'F']
|
||||
}
|
||||
|
||||
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
|
||||
fn breadth_first_search_path(graph map[string][]string, vertex string, target string) []string {
|
||||
mut path := []string{}
|
||||
|
|
@ -24,18 +39,3 @@ fn breadth_first_search_path(graph map[string][]string, vertex string, target st
|
|||
}
|
||||
return path
|
||||
}
|
||||
|
||||
fn main() {
|
||||
graph := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
println('Graph: $graph')
|
||||
path := breadth_first_search_path(graph, 'A', 'F')
|
||||
println('The shortest path from node A to node F is: $path')
|
||||
assert path == ['A', 'C', 'F']
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// Author: ccs
|
||||
// I follow literally code in C, done many years ago
|
||||
fn main() {
|
||||
// Adjacency matrix as a map
|
||||
graph := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
println('Graph: $graph')
|
||||
path := breadth_first_search_path(graph, 'A', 'F')
|
||||
println('\n The shortest path from node A to node F is: $path.reverse()')
|
||||
}
|
||||
|
||||
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
|
||||
fn breadth_first_search_path(graph map[string][]string, start string, target string) []string {
|
||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||
mut queue := []string{} // a queue ... many paths
|
||||
// all_nodes := graph.keys() // get a key of this map
|
||||
n_nodes := graph.len // numbers of nodes of this graph
|
||||
// a map to store all the nodes visited to avoid cycles
|
||||
// start all them with False, not visited yet
|
||||
mut visited := a_map_nodes_bool(n_nodes) // a map fully
|
||||
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||
queue << start // first arrival
|
||||
for queue.len != 0 {
|
||||
mut node := departure(mut queue) // get the front node and remove it
|
||||
if visited[node] == false { // check if this node is already visited
|
||||
// if no ... test it searchinf for a final node
|
||||
visited[node] = true // means: visit this node
|
||||
if node == target {
|
||||
path = build_path_reverse(graph, start, node, visited)
|
||||
return path
|
||||
}
|
||||
// Expansion of node removed from queue
|
||||
print('\n Expansion of node $node (true/false): ${graph[node]}')
|
||||
// take all nodes from the node
|
||||
for vertex in graph[node] { // println("\n ...${vertex}")
|
||||
// not explored yet
|
||||
if visited[vertex] == false {
|
||||
queue << vertex
|
||||
}
|
||||
}
|
||||
print('\n QUEUE: $queue (only not visited) \n Visited: $visited')
|
||||
}
|
||||
}
|
||||
path = ['Path not found, problem in the Graph, start or end nodes! ']
|
||||
return path
|
||||
}
|
||||
|
||||
// Creating a map for VISITED nodes ...
|
||||
// starting by false ===> means this node was not visited yet
|
||||
fn a_map_nodes_bool(size int) map[string]bool {
|
||||
mut my_map := map[string]bool{} // look this map ...
|
||||
base := u8(65)
|
||||
mut key := base.ascii_str()
|
||||
for i in 0 .. size {
|
||||
key = u8(base + i).ascii_str()
|
||||
my_map[key] = false
|
||||
}
|
||||
return my_map
|
||||
}
|
||||
|
||||
// classical removing of a node from the start of a queue
|
||||
fn departure(mut queue []string) string {
|
||||
mut x := queue[0]
|
||||
queue.delete(0)
|
||||
return x
|
||||
}
|
||||
|
||||
// Based in the current node that is final, search for its parent, already visited, up to the root or start node
|
||||
fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
|
||||
print('\n\n Nodes visited (true) or no (false): $visited')
|
||||
array_of_nodes := graph.keys()
|
||||
mut current := final
|
||||
mut path := []string{}
|
||||
path << current
|
||||
|
||||
for (current != start) {
|
||||
for i in array_of_nodes {
|
||||
if (current in graph[i]) && (visited[i] == true) {
|
||||
current = i
|
||||
break // the first ocurrence is enough
|
||||
}
|
||||
}
|
||||
path << current // update the path tracked
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
// Author: ccs
|
||||
// I follow literally code in C, done many years ago
|
||||
|
||||
fn main() {
|
||||
// Adjacency matrix as a map
|
||||
// Example 01
|
||||
graph_01 := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['F', 'B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
// Example 02
|
||||
graph_02 := {
|
||||
'A': ['B', 'C', 'D']
|
||||
'B': ['E']
|
||||
'C': ['F']
|
||||
'D': ['E']
|
||||
'E': ['H']
|
||||
'F': ['H']
|
||||
'G': ['H']
|
||||
'H': ['E', 'F', 'G']
|
||||
}
|
||||
// println('Graph: $graph')
|
||||
path_01 := depth_first_search_path(graph_01, 'A', 'F')
|
||||
println('\n Graph_01: a first path from node A to node F is: $path_01.reverse()')
|
||||
path_02 := depth_first_search_path(graph_02, 'A', 'H')
|
||||
println('\n Graph_02: a first path from node A to node F is: $path_02.reverse()')
|
||||
}
|
||||
|
||||
// Depth-First Search (BFS) allows you to find a path between two nodes in the graph.
|
||||
fn depth_first_search_path(graph map[string][]string, start string, target string) []string {
|
||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||
mut stack := []string{} // a stack ... many nodes
|
||||
// all_nodes := graph.keys() // get a key of this map
|
||||
n_nodes := graph.len // numbers of nodes of this graph
|
||||
mut visited := a_map_nodes_bool(n_nodes) // a map fully
|
||||
// false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||
|
||||
stack << start // first push on the stack
|
||||
for stack.len > 0 {
|
||||
mut node := stack.pop() // get the top node and remove it from the stack
|
||||
|
||||
// check if this node is already visited
|
||||
if visited[node] == false {
|
||||
// if no ... test it searchin for a final node
|
||||
visited[node] = true // means: node visited
|
||||
if node == target {
|
||||
path = build_path_reverse(graph, start, node, visited)
|
||||
return path
|
||||
}
|
||||
// Exploring of node removed from stack and add its relatives
|
||||
print('\n Exploring of node $node (true/false): ${graph[node]}')
|
||||
// graph[node].reverse() take a classical choice for DFS
|
||||
// at most os left in this case.
|
||||
// use vertex in graph[node] the choice is right
|
||||
|
||||
// take all nodes from the node
|
||||
for vertex in graph[node].reverse() {
|
||||
// println("\n ...${vertex}")
|
||||
// not explored yet
|
||||
if visited[vertex] == false {
|
||||
stack << vertex
|
||||
}
|
||||
}
|
||||
print('\n Stack: $stack (only not visited) \n Visited: $visited')
|
||||
}
|
||||
}
|
||||
path = ['Path not found, problem in the Graph, start or end nodes! ']
|
||||
return path
|
||||
}
|
||||
|
||||
// Creating a map for nodes not VISITED visited ...
|
||||
// starting by false ===> means this node was not visited yet
|
||||
fn a_map_nodes_bool(size int) map[string]bool {
|
||||
mut my_map := map[string]bool{} // look this map ...
|
||||
for i in 0 .. size {
|
||||
my_map[u8(65 + i).ascii_str()] = false
|
||||
}
|
||||
return my_map
|
||||
}
|
||||
|
||||
// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node
|
||||
fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
|
||||
print('\n\n Nodes visited (true) or no (false): $visited')
|
||||
array_of_nodes := graph.keys()
|
||||
mut current := final
|
||||
mut path := []string{}
|
||||
path << current
|
||||
|
||||
for current != start {
|
||||
for i in array_of_nodes {
|
||||
if (current in graph[i]) && (visited[i] == true) {
|
||||
current = i
|
||||
break // the first ocurrence is enough
|
||||
}
|
||||
}
|
||||
path << current // updating the path tracked
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
|
@ -931,7 +931,7 @@ fn test_u64_keys() {
|
|||
m[i]++
|
||||
assert m[i] == i + 1
|
||||
}
|
||||
assert m.len == end
|
||||
assert u64(m.len) == end
|
||||
keys := m.keys()
|
||||
for i in u64(0) .. end {
|
||||
assert keys[i] == i
|
||||
|
|
|
|||
|
|
@ -919,7 +919,7 @@ fn test_u64_keys() {
|
|||
m[i]++
|
||||
assert m[i] == i + 1
|
||||
}
|
||||
assert m.len == end
|
||||
assert u64(m.len) == end
|
||||
keys := m.keys()
|
||||
for i in u64(0) .. end {
|
||||
assert keys[i] == i
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ fn help_cmd() Command {
|
|||
}
|
||||
}
|
||||
|
||||
// print_help_for_command outputs the help message of `help_cmd`.
|
||||
pub fn print_help_for_command(help_cmd Command) ? {
|
||||
if help_cmd.args.len > 0 {
|
||||
mut cmd := help_cmd.parent
|
||||
|
|
@ -54,6 +55,7 @@ pub fn print_help_for_command(help_cmd Command) ? {
|
|||
}
|
||||
}
|
||||
|
||||
// help_message returns a generated help message as a `string` for the `Command`.
|
||||
pub fn (cmd Command) help_message() string {
|
||||
mut help := ''
|
||||
help += 'Usage: $cmd.full_name()'
|
||||
|
|
|
|||
|
|
@ -51,8 +51,7 @@ const (
|
|||
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
||||
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
||||
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd],
|
||||
'Test With Truncation'.bytes(),
|
||||
'Test Using Larger Than Block-Size Key - Hash Key First'.bytes(),
|
||||
'Test With Truncation'.bytes(), 'Test Using Larger Than Block-Size Key - Hash Key First'.bytes(),
|
||||
'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data'.bytes()]
|
||||
)
|
||||
|
||||
|
|
|
|||
140
vlib/gg/draw.c.v
140
vlib/gg/draw.c.v
|
|
@ -278,72 +278,114 @@ pub fn (ctx &Context) draw_rounded_rect_empty(x f32, y f32, w f32, h f32, radius
|
|||
// `x`,`y` is the top-left corner of the rectangle.
|
||||
// `w` is the width, `h` is the height .
|
||||
// `radius` is the radius of the corner-rounding in pixels.
|
||||
// `c` is the color of the outline.
|
||||
// `c` is the color of the filled.
|
||||
pub fn (ctx &Context) draw_rounded_rect_filled(x f32, y f32, w f32, h f32, radius f32, c gx.Color) {
|
||||
assert w > 0 && h > 0 && radius >= 0
|
||||
if c.a != 255 {
|
||||
sgl.load_pipeline(ctx.timage_pip)
|
||||
}
|
||||
sgl.c4b(c.r, c.g, c.b, c.a)
|
||||
sgl.begin_triangle_strip()
|
||||
mut theta := f32(0)
|
||||
mut xx := f32(0)
|
||||
mut yy := f32(0)
|
||||
r := radius * ctx.scale
|
||||
mut radians := f32(0)
|
||||
mut new_radius := radius
|
||||
if w >= h && radius > h / 2 {
|
||||
new_radius = h / 2
|
||||
} else if radius > w / 2 {
|
||||
new_radius = w / 2
|
||||
}
|
||||
|
||||
r := new_radius * ctx.scale
|
||||
nx := x * ctx.scale
|
||||
ny := y * ctx.scale
|
||||
width := w * ctx.scale
|
||||
height := h * ctx.scale
|
||||
segments := 2 * math.pi * r
|
||||
segdiv := segments / 4
|
||||
rb := 0
|
||||
lb := int(rb + segdiv)
|
||||
lt := int(lb + segdiv)
|
||||
rt := int(lt + segdiv)
|
||||
// left top
|
||||
lx := nx + r
|
||||
ly := ny + r
|
||||
for i in lt .. rt {
|
||||
theta = 2 * f32(math.pi) * f32(i) / segments
|
||||
xx = r * math.cosf(theta)
|
||||
yy = r * math.sinf(theta)
|
||||
sgl.v2f(xx + lx, yy + ly)
|
||||
sgl.v2f(lx, ly)
|
||||
|
||||
// left top quarter
|
||||
sgl.begin_triangle_strip()
|
||||
ltx := nx + r
|
||||
lty := ny + r
|
||||
for i in 0 .. 91 {
|
||||
if r == 0 {
|
||||
break
|
||||
}
|
||||
radians = f32(math.radians(i))
|
||||
xx = r * math.cosf(radians)
|
||||
yy = r * math.sinf(radians)
|
||||
sgl.v2f(ltx - xx, lty - yy)
|
||||
sgl.v2f(ltx, lty)
|
||||
}
|
||||
// right top
|
||||
mut rx := nx + width - r
|
||||
mut ry := ny + r
|
||||
for i in rt .. int(segments) {
|
||||
theta = 2 * f32(math.pi) * f32(i) / segments
|
||||
xx = r * math.cosf(theta)
|
||||
yy = r * math.sinf(theta)
|
||||
sgl.v2f(xx + rx, yy + ry)
|
||||
sgl.v2f(rx, ry)
|
||||
sgl.end()
|
||||
|
||||
// right top quarter
|
||||
sgl.begin_triangle_strip()
|
||||
rtx := nx + width - r
|
||||
rty := ny + r
|
||||
for i in 0 .. 91 {
|
||||
if r == 0 {
|
||||
break
|
||||
}
|
||||
radians = f32(math.radians(i))
|
||||
xx = r * math.cosf(radians)
|
||||
yy = r * math.sinf(radians)
|
||||
sgl.v2f(rtx + xx, rty - yy)
|
||||
sgl.v2f(rtx, rty)
|
||||
}
|
||||
// right bottom
|
||||
mut rbx := rx
|
||||
mut rby := ny + height - r
|
||||
for i in rb .. lb {
|
||||
theta = 2 * f32(math.pi) * f32(i) / segments
|
||||
xx = r * math.cosf(theta)
|
||||
yy = r * math.sinf(theta)
|
||||
sgl.v2f(xx + rbx, yy + rby)
|
||||
sgl.end()
|
||||
|
||||
// right bottom quarter
|
||||
sgl.begin_triangle_strip()
|
||||
rbx := nx + width - r
|
||||
rby := ny + height - r
|
||||
for i in 0 .. 91 {
|
||||
if r == 0 {
|
||||
break
|
||||
}
|
||||
radians = f32(math.radians(i))
|
||||
xx = r * math.cosf(radians)
|
||||
yy = r * math.sinf(radians)
|
||||
sgl.v2f(rbx + xx, rby + yy)
|
||||
sgl.v2f(rbx, rby)
|
||||
}
|
||||
// left bottom
|
||||
mut lbx := lx
|
||||
mut lby := ny + height - r
|
||||
for i in lb .. lt {
|
||||
theta = 2 * f32(math.pi) * f32(i) / segments
|
||||
xx = r * math.cosf(theta)
|
||||
yy = r * math.sinf(theta)
|
||||
sgl.v2f(xx + lbx, yy + lby)
|
||||
sgl.end()
|
||||
|
||||
// left bottom quarter
|
||||
sgl.begin_triangle_strip()
|
||||
lbx := nx + r
|
||||
lby := ny + height - r
|
||||
for i in 0 .. 91 {
|
||||
if r == 0 {
|
||||
break
|
||||
}
|
||||
radians = f32(math.radians(i))
|
||||
xx = r * math.cosf(radians)
|
||||
yy = r * math.sinf(radians)
|
||||
sgl.v2f(lbx - xx, lby + yy)
|
||||
sgl.v2f(lbx, lby)
|
||||
}
|
||||
sgl.v2f(lx + xx, ly)
|
||||
sgl.v2f(lx, ly)
|
||||
sgl.end()
|
||||
|
||||
// Separate drawing is to prevent transparent color overlap
|
||||
// top rectangle
|
||||
sgl.begin_quads()
|
||||
sgl.v2f(ltx, ny)
|
||||
sgl.v2f(rtx, ny)
|
||||
sgl.v2f(rtx, rty)
|
||||
sgl.v2f(ltx, lty)
|
||||
sgl.end()
|
||||
// middle rectangle
|
||||
sgl.begin_quads()
|
||||
sgl.v2f(nx, ny + r)
|
||||
sgl.v2f(rtx + r, rty)
|
||||
sgl.v2f(rbx + r, rby)
|
||||
sgl.v2f(nx, lby)
|
||||
sgl.end()
|
||||
// bottom rectangle
|
||||
sgl.begin_quads()
|
||||
sgl.v2f(lx, ly)
|
||||
sgl.v2f(rx, ry)
|
||||
sgl.v2f(rbx, rby)
|
||||
sgl.v2f(lbx, lby)
|
||||
sgl.v2f(rbx, rby)
|
||||
sgl.v2f(rbx, ny + height)
|
||||
sgl.v2f(lbx, ny + height)
|
||||
sgl.end()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -242,8 +242,7 @@ const (
|
|||
cookie: [&http.Cookie{
|
||||
name: 'cookie-1'
|
||||
value: 'v1'
|
||||
},
|
||||
&http.Cookie{
|
||||
}, &http.Cookie{
|
||||
name: 'cookie-2'
|
||||
value: 'v2'
|
||||
},
|
||||
|
|
@ -294,8 +293,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['ASP.NET_SessionId=foo; path=/; HttpOnly']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'ASP.NET_SessionId'
|
||||
value: 'foo'
|
||||
path: '/'
|
||||
|
|
@ -307,8 +305,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['samesitedefault=foo; SameSite']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'samesitedefault'
|
||||
value: 'foo'
|
||||
same_site: .same_site_default_mode
|
||||
|
|
@ -319,8 +316,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['samesitelax=foo; SameSite=Lax']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'samesitelax'
|
||||
value: 'foo'
|
||||
same_site: .same_site_lax_mode
|
||||
|
|
@ -331,8 +327,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['samesitestrict=foo; SameSite=Strict']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'samesitestrict'
|
||||
value: 'foo'
|
||||
same_site: .same_site_strict_mode
|
||||
|
|
@ -343,8 +338,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['samesitenone=foo; SameSite=None']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'samesitenone'
|
||||
value: 'foo'
|
||||
same_site: .same_site_none_mode
|
||||
|
|
@ -357,8 +351,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-1=a z']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-1'
|
||||
value: 'a z'
|
||||
raw: 'special-1=a z'
|
||||
|
|
@ -368,8 +361,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-2=" z"']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-2'
|
||||
value: ' z'
|
||||
raw: 'special-2=" z"'
|
||||
|
|
@ -379,8 +371,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-3="a "']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-3'
|
||||
value: 'a '
|
||||
raw: 'special-3="a "'
|
||||
|
|
@ -390,8 +381,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-4=" "']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-4'
|
||||
value: ' '
|
||||
raw: 'special-4=" "'
|
||||
|
|
@ -401,8 +391,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-5=a,z']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-5'
|
||||
value: 'a,z'
|
||||
raw: 'special-5=a,z'
|
||||
|
|
@ -412,8 +401,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-6=",z"']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-6'
|
||||
value: ',z'
|
||||
raw: 'special-6=",z"'
|
||||
|
|
@ -423,8 +411,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-7=","']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-7'
|
||||
value: ','
|
||||
raw: 'special-8=","'
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ pub fn (mut ws Client) parse_frame_header() ?Frame {
|
|||
buffer[bytes_read] = rbuff[0]
|
||||
bytes_read++
|
||||
// parses the first two header bytes to get basic frame information
|
||||
if bytes_read == u64(websocket.header_len_offset) {
|
||||
if bytes_read == websocket.header_len_offset {
|
||||
frame.fin = (buffer[0] & 0x80) == 0x80
|
||||
frame.rsv1 = (buffer[0] & 0x40) == 0x40
|
||||
frame.rsv2 = (buffer[0] & 0x20) == 0x20
|
||||
|
|
@ -249,7 +249,7 @@ pub fn (mut ws Client) parse_frame_header() ?Frame {
|
|||
break
|
||||
}
|
||||
}
|
||||
if frame.payload_len == 126 && bytes_read == u64(websocket.extended_payload16_end_byte) {
|
||||
if frame.payload_len == 126 && bytes_read == websocket.extended_payload16_end_byte {
|
||||
frame.header_len += 2
|
||||
frame.payload_len = 0
|
||||
frame.payload_len |= int(u32(buffer[2]) << 8)
|
||||
|
|
@ -259,7 +259,7 @@ pub fn (mut ws Client) parse_frame_header() ?Frame {
|
|||
break
|
||||
}
|
||||
}
|
||||
if frame.payload_len == 127 && bytes_read == u64(websocket.extended_payload64_end_byte) {
|
||||
if frame.payload_len == 127 && bytes_read == websocket.extended_payload64_end_byte {
|
||||
frame.header_len += 8
|
||||
// these shift operators needs 64 bit on clang with -prod flag
|
||||
mut payload_len := u64(0)
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ pub fn rmdir_all(path string) ? {
|
|||
}
|
||||
|
||||
// is_dir_empty will return a `bool` whether or not `path` is empty.
|
||||
// Note that it will return `true` if `path` does not exist.
|
||||
[manualfree]
|
||||
pub fn is_dir_empty(path string) bool {
|
||||
items := ls(path) or { return true }
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ fn test_open_file() {
|
|||
mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) }
|
||||
file.write_string(hello) or { panic(err) }
|
||||
file.close()
|
||||
assert hello.len == os.file_size(filename)
|
||||
assert u64(hello.len) == os.file_size(filename)
|
||||
read_hello := os.read_file(filename) or { panic('error reading file $filename') }
|
||||
assert hello == read_hello
|
||||
os.rm(filename) or { panic(err) }
|
||||
|
|
@ -58,7 +58,7 @@ fn test_open_file_binary() {
|
|||
bytes := hello.bytes()
|
||||
unsafe { file.write_ptr(bytes.data, bytes.len) }
|
||||
file.close()
|
||||
assert hello.len == os.file_size(filename)
|
||||
assert u64(hello.len) == os.file_size(filename)
|
||||
read_hello := os.read_bytes(filename) or { panic('error reading file $filename') }
|
||||
assert bytes == read_hello
|
||||
os.rm(filename) or { panic(err) }
|
||||
|
|
@ -100,7 +100,7 @@ fn test_create_file() ? {
|
|||
filename := './test1.txt'
|
||||
hello := 'hello world!'
|
||||
create_and_write_to_file(filename, hello) ?
|
||||
assert hello.len == os.file_size(filename)
|
||||
assert u64(hello.len) == os.file_size(filename)
|
||||
os.rm(filename) or { panic(err) }
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ fn test_write_and_read_string_to_file() {
|
|||
filename := './test1.txt'
|
||||
hello := 'hello world!'
|
||||
os.write_file(filename, hello) or { panic(err) }
|
||||
assert hello.len == os.file_size(filename)
|
||||
assert u64(hello.len) == os.file_size(filename)
|
||||
read_hello := os.read_file(filename) or { panic('error reading file $filename') }
|
||||
assert hello == read_hello
|
||||
os.rm(filename) or { panic(err) }
|
||||
|
|
@ -157,7 +157,7 @@ fn test_write_and_read_bytes() {
|
|||
// compare the length of the array with the file size (have to match).
|
||||
unsafe { file_write.write_ptr(payload.data, 5) }
|
||||
file_write.close()
|
||||
assert payload.len == os.file_size(file_name)
|
||||
assert u64(payload.len) == os.file_size(file_name)
|
||||
mut file_read := os.open(os.real_path(file_name)) or {
|
||||
eprintln('failed to open file $file_name')
|
||||
return
|
||||
|
|
@ -355,6 +355,12 @@ fn test_mv() {
|
|||
assert !os.is_dir(expected)
|
||||
}
|
||||
|
||||
fn test_is_dir_empty() {
|
||||
// Test that is_dir_empty returns true on
|
||||
// non-existent directories ***as stated in it's doc string***
|
||||
assert os.is_dir_empty('dir that does not exist at all')
|
||||
}
|
||||
|
||||
fn test_cp_all() {
|
||||
// fileX -> dir/fileX
|
||||
// Note: clean up of the files happens inside the cleanup_leftovers function
|
||||
|
|
@ -786,7 +792,7 @@ fn test_truncate() ? {
|
|||
mut f := os.create(filename) ?
|
||||
f.write_string(hello) ?
|
||||
f.close()
|
||||
assert hello.len == os.file_size(filename)
|
||||
assert u64(hello.len) == os.file_size(filename)
|
||||
newlen := u64(40000)
|
||||
os.truncate(filename, newlen) or { panic(err) }
|
||||
assert newlen == os.file_size(filename)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ import strings
|
|||
* Inits
|
||||
*
|
||||
******************************************************************************/
|
||||
// regex create a regex object from the query string, retunr RE object and errors as re_err, err_pos
|
||||
// regex_base returns a regex object (`RE`) generated from `pattern` string and
|
||||
// detailed information in re_err, err_pos, if an error occurred.
|
||||
pub fn regex_base(pattern string) (RE, int, int) {
|
||||
// init regex
|
||||
mut re := RE{}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
/*
|
||||
* ATTENTION! Do not use this file as an example!
|
||||
* For that, please look at `channel_select_2_test.v` or `channel_select_3_test.v`
|
||||
*
|
||||
* This test case uses the implementation in `sync/channels.v` directly
|
||||
* in order to test it independently from the support in the core language
|
||||
*/
|
||||
|
||||
module sync
|
||||
|
||||
// vtest retry: 6
|
||||
|
||||
// ATTENTION! Do not use this file as an example!
|
||||
// For that, please look at `channel_select_2_test.v` or `channel_select_3_test.v`
|
||||
// This test case uses the implementation in `sync/channels.v` directly
|
||||
// in order to test it independently from the support in the core language
|
||||
import time
|
||||
|
||||
fn do_rec_i64(mut ch Channel) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ fn test_count_10_times_1_cycle_should_result_10_cycles_with_sync() {
|
|||
go count_one_cycle(mut counter, mut wg)
|
||||
}
|
||||
wg.wait()
|
||||
assert counter.counter == desired_iterations
|
||||
assert counter.counter == u64(desired_iterations)
|
||||
eprintln(' with synchronization the counter is: ${counter.counter:10} , expectedly == ${desired_iterations:10}')
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1821,6 +1821,9 @@ pub fn (stmt Stmt) check_c_expr() ? {
|
|||
AssignStmt {
|
||||
return
|
||||
}
|
||||
ForCStmt, ForInStmt, ForStmt {
|
||||
return
|
||||
}
|
||||
ExprStmt {
|
||||
if stmt.expr.is_expr() {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -206,6 +206,14 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
|
|||
if v.pref.os == .macos && os.exists('/opt/procursus') {
|
||||
ccoptions.linker_flags << '-Wl,-rpath,/opt/procursus/lib'
|
||||
}
|
||||
mut user_darwin_version := 999_999_999
|
||||
mut user_darwin_ppc := false
|
||||
$if macos {
|
||||
user_darwin_version = os.uname().release.split('.')[0].int()
|
||||
if os.uname().machine == 'Power Macintosh' {
|
||||
user_darwin_ppc = true
|
||||
}
|
||||
}
|
||||
ccoptions.debug_mode = v.pref.is_debug
|
||||
ccoptions.guessed_compiler = v.pref.ccompiler
|
||||
if ccoptions.guessed_compiler == 'cc' && v.pref.is_prod {
|
||||
|
|
@ -252,7 +260,10 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
|
|||
}
|
||||
if ccoptions.is_cc_gcc {
|
||||
if ccoptions.debug_mode {
|
||||
debug_options = ['-g', '-no-pie']
|
||||
debug_options = ['-g']
|
||||
if user_darwin_version > 9 {
|
||||
debug_options << '-no-pie'
|
||||
}
|
||||
}
|
||||
optimization_options = ['-O3', '-fno-strict-aliasing', '-flto']
|
||||
}
|
||||
|
|
@ -334,7 +345,7 @@ fn (mut v Builder) setup_ccompiler_options(ccompiler string) {
|
|||
}
|
||||
// macOS code can include objective C TODO remove once objective C is replaced with C
|
||||
if v.pref.os == .macos || v.pref.os == .ios {
|
||||
if !ccoptions.is_cc_tcc {
|
||||
if !ccoptions.is_cc_tcc && !user_darwin_ppc {
|
||||
ccoptions.source_args << '-x objective-c'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,7 +335,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
left_elem_type := c.table.unaliased_type(left_info.elem_type)
|
||||
right_info := right_sym.info as ast.Array
|
||||
right_elem_type := c.table.unaliased_type(right_info.elem_type)
|
||||
if left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type {
|
||||
if left_type_unwrapped.nr_muls() == right_type_unwrapped.nr_muls()
|
||||
&& left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,9 @@ pub fn (mut c Checker) check_expected_call_arg(got ast.Type, expected_ ast.Type,
|
|||
}
|
||||
return
|
||||
}
|
||||
return error('cannot use `$got_typ_str` as `$expected_typ_str`')
|
||||
if got != ast.void_type {
|
||||
return error('cannot use `$got_typ_str` as `$expected_typ_str`')
|
||||
}
|
||||
}
|
||||
|
||||
// helper method to check if the type is of the same module.
|
||||
|
|
@ -689,3 +691,38 @@ pub fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr
|
|||
c.need_recheck_generic_fns = true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c &Checker) sizeof_integer(a ast.Type) int {
|
||||
t := if a in ast.unsigned_integer_type_idxs { a.flip_signedness() } else { a }
|
||||
r := match t {
|
||||
ast.char_type_idx, ast.i8_type_idx {
|
||||
1
|
||||
}
|
||||
ast.i16_type_idx {
|
||||
2
|
||||
}
|
||||
ast.int_type_idx {
|
||||
4
|
||||
}
|
||||
ast.rune_type_idx {
|
||||
4
|
||||
}
|
||||
ast.i64_type_idx {
|
||||
8
|
||||
}
|
||||
ast.isize_type_idx {
|
||||
if c.pref.m64 { 8 } else { 4 }
|
||||
}
|
||||
ast.int_literal_type {
|
||||
s := c.table.type_to_str(a)
|
||||
panic('`$s` has unknown size')
|
||||
0
|
||||
}
|
||||
else {
|
||||
s := c.table.type_to_str(a)
|
||||
panic('`$s` is not an integer')
|
||||
0
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
|
|
|||
|
|
@ -640,6 +640,18 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
rt := c.table.sym(right_type).name
|
||||
c.error('negative value cannot be compared with `$rt`', node.left.pos)
|
||||
}
|
||||
} else if is_left_type_signed != is_right_type_signed
|
||||
&& left_type != ast.int_literal_type_idx
|
||||
&& right_type != ast.int_literal_type_idx {
|
||||
ls := c.sizeof_integer(left_type)
|
||||
rs := c.sizeof_integer(right_type)
|
||||
// prevent e.g. `u32 == i16` but not `u16 == i32` as max_u16 fits in i32
|
||||
// TODO u32 == i32, change < to <=
|
||||
if (is_left_type_signed && ls < rs) || (is_right_type_signed && rs < ls) {
|
||||
lt := c.table.sym(left_type).name
|
||||
rt := c.table.sym(right_type).name
|
||||
c.error('`$lt` cannot be compared with `$rt`', node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1663,7 +1675,9 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
|||
c.inside_selector_expr = old_selector_expr
|
||||
c.using_new_err_struct = using_new_err_struct_save
|
||||
if typ == ast.void_type_idx {
|
||||
c.error('`void` type has no fields', node.pos)
|
||||
// This means that the field has an undefined type.
|
||||
// This error was handled before.
|
||||
// c.error('`void` type has no fields', node.pos)
|
||||
return ast.void_type
|
||||
}
|
||||
node.expr_type = typ
|
||||
|
|
@ -3683,8 +3697,8 @@ pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
|
|||
for mut expr is ast.ParExpr {
|
||||
expr = expr.expr
|
||||
}
|
||||
if expr in [ast.BoolLiteral, ast.CallExpr, ast.CharLiteral, ast.FloatLiteral,
|
||||
ast.IntegerLiteral, ast.InfixExpr, ast.StringLiteral, ast.StringInterLiteral] {
|
||||
if expr in [ast.BoolLiteral, ast.CallExpr, ast.CharLiteral, ast.FloatLiteral, ast.IntegerLiteral,
|
||||
ast.InfixExpr, ast.StringLiteral, ast.StringInterLiteral] {
|
||||
c.error('cannot take the address of $expr', node.pos)
|
||||
}
|
||||
if mut node.right is ast.IndexExpr {
|
||||
|
|
|
|||
|
|
@ -578,6 +578,17 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
found = true
|
||||
return ast.string_type
|
||||
}
|
||||
if !found && node.left is ast.CallExpr {
|
||||
c.expr(node.left)
|
||||
expr := node.left as ast.CallExpr
|
||||
sym := c.table.sym(expr.return_type)
|
||||
if sym.kind == .function {
|
||||
info := sym.info as ast.FnType
|
||||
node.return_type = info.func.return_type
|
||||
found = true
|
||||
func = info.func
|
||||
}
|
||||
}
|
||||
// already prefixed (mod.fn) or C/builtin/main
|
||||
if !found {
|
||||
if f := c.table.find_fn(fn_name) {
|
||||
|
|
@ -895,6 +906,16 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
if param.typ.has_flag(.generic) {
|
||||
continue
|
||||
}
|
||||
if param_typ_sym.kind == .array && arg_typ_sym.kind == .array {
|
||||
param_info := param_typ_sym.info as ast.Array
|
||||
param_elem_type := c.table.unaliased_type(param_info.elem_type)
|
||||
arg_info := arg_typ_sym.info as ast.Array
|
||||
arg_elem_type := c.table.unaliased_type(arg_info.elem_type)
|
||||
if param.typ.nr_muls() == arg_typ.nr_muls()
|
||||
&& param_info.nr_dims == arg_info.nr_dims && param_elem_type == arg_elem_type {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if c.pref.translated || c.file.is_translated {
|
||||
// TODO duplicated logic in check_types() (check_types.v)
|
||||
// Allow enums to be used as ints and vice versa in translated code
|
||||
|
|
@ -1389,6 +1410,19 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
|||
// if arg_typ_sym.kind == .string && typ_sym.has_method('str') {
|
||||
// continue
|
||||
// }
|
||||
param_typ_sym := c.table.sym(exp_arg_typ)
|
||||
arg_typ_sym := c.table.sym(got_arg_typ)
|
||||
if param_typ_sym.kind == .array && arg_typ_sym.kind == .array {
|
||||
param_info := param_typ_sym.info as ast.Array
|
||||
param_elem_type := c.table.unaliased_type(param_info.elem_type)
|
||||
arg_info := arg_typ_sym.info as ast.Array
|
||||
arg_elem_type := c.table.unaliased_type(arg_info.elem_type)
|
||||
if exp_arg_typ.nr_muls() == got_arg_typ.nr_muls()
|
||||
&& param_info.nr_dims == arg_info.nr_dims
|
||||
&& param_elem_type == arg_elem_type {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if got_arg_typ != ast.void_type {
|
||||
c.error('$err.msg() in argument ${i + 1} to `${left_sym.name}.$method_name`',
|
||||
arg.pos)
|
||||
|
|
@ -1743,6 +1777,9 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type ast.
|
|||
mut ret_type := ast.void_type
|
||||
match method_name {
|
||||
'clone', 'move' {
|
||||
if node.args.len != 0 {
|
||||
c.error('`.${method_name}()` does not have any arguments', node.args[0].pos)
|
||||
}
|
||||
if method_name[0] == `m` {
|
||||
c.fail_if_immutable(node.left)
|
||||
}
|
||||
|
|
@ -1754,6 +1791,9 @@ fn (mut c Checker) map_builtin_method_call(mut node ast.CallExpr, left_type ast.
|
|||
ret_type = ret_type.clear_flag(.shared_f)
|
||||
}
|
||||
'keys' {
|
||||
if node.args.len != 0 {
|
||||
c.error('`.keys()` does not have any arguments', node.args[0].pos)
|
||||
}
|
||||
info := left_sym.info as ast.Map
|
||||
typ := c.table.find_or_register_array(info.key_type)
|
||||
ret_type = ast.Type(typ)
|
||||
|
|
@ -1878,6 +1918,9 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
|
|||
c.check_map_and_filter(false, elem_typ, node)
|
||||
node.return_type = ast.bool_type
|
||||
} else if method_name == 'clone' {
|
||||
if node.args.len != 0 {
|
||||
c.error('`.clone()` does not have any arguments', node.args[0].pos)
|
||||
}
|
||||
// need to return `array_xxx` instead of `array`
|
||||
// in ['clone', 'str'] {
|
||||
node.receiver_type = left_type.ref()
|
||||
|
|
@ -1895,19 +1938,27 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
|
|||
// c.warn('use `value in arr` instead of `arr.contains(value)`', node.pos)
|
||||
if node.args.len != 1 {
|
||||
c.error('`.contains()` expected 1 argument, but got $node.args.len', node.pos)
|
||||
} else {
|
||||
arg_typ := ast.mktyp(c.expr(node.args[0].expr))
|
||||
elem_typ_str := c.table.type_to_str(elem_typ)
|
||||
arg_typ_str := c.table.type_to_str(arg_typ)
|
||||
if !left_sym.has_method('contains') && elem_typ_str != arg_typ_str {
|
||||
c.error('`.contains()` expected `$elem_typ_str` argument, but got `$arg_typ_str`',
|
||||
node.pos)
|
||||
} else if !left_sym.has_method('contains') {
|
||||
arg_typ := c.expr(node.args[0].expr)
|
||||
c.check_expected_call_arg(arg_typ, elem_typ, node.language, node.args[0]) or {
|
||||
c.error('$err.msg() in argument 1 to `.contains()`', node.args[0].pos)
|
||||
}
|
||||
}
|
||||
node.return_type = ast.bool_type
|
||||
} else if method_name == 'index' {
|
||||
if node.args.len != 1 {
|
||||
c.error('`.index()` expected 1 argument, but got $node.args.len', node.pos)
|
||||
} else if !left_sym.has_method('index') {
|
||||
arg_typ := c.expr(node.args[0].expr)
|
||||
c.check_expected_call_arg(arg_typ, elem_typ, node.language, node.args[0]) or {
|
||||
c.error('$err.msg() in argument 1 to `.index()`', node.args[0].pos)
|
||||
}
|
||||
}
|
||||
node.return_type = ast.int_type
|
||||
} else if method_name in ['first', 'last', 'pop'] {
|
||||
if node.args.len != 0 {
|
||||
c.error('`.${method_name}()` does not have any arguments', node.args[0].pos)
|
||||
}
|
||||
node.return_type = array_info.elem_type
|
||||
if method_name == 'pop' {
|
||||
c.fail_if_immutable(node.left)
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
|
|||
node.scope.update_var_type(node.key_var, key_type)
|
||||
}
|
||||
mut value_type := c.table.value_type(typ)
|
||||
if sym.kind == .string {
|
||||
value_type = ast.byte_type
|
||||
}
|
||||
if value_type == ast.void_type || typ.has_flag(.optional) {
|
||||
if typ != ast.void_type {
|
||||
c.error('for in: cannot index `${c.table.type_to_str(typ)}`', node.cond.pos())
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
|
|||
c.smartcast_if_conds(node.right, mut scope)
|
||||
} else if node.op == .key_is {
|
||||
right_expr := node.right
|
||||
mut right_type := match right_expr {
|
||||
right_type := match right_expr {
|
||||
ast.TypeNode {
|
||||
right_expr.typ
|
||||
}
|
||||
|
|
@ -308,11 +308,10 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
|
|||
ast.Type(0)
|
||||
}
|
||||
}
|
||||
right_type = c.unwrap_generic(right_type)
|
||||
if right_type != ast.Type(0) {
|
||||
left_sym := c.table.sym(node.left_type)
|
||||
right_sym := c.table.sym(right_type)
|
||||
mut expr_type := c.unwrap_generic(c.expr(node.left))
|
||||
mut expr_type := c.expr(node.left)
|
||||
if left_sym.kind == .aggregate {
|
||||
expr_type = (left_sym.info as ast.Aggregate).sum_type
|
||||
}
|
||||
|
|
@ -322,7 +321,7 @@ fn (mut c Checker) smartcast_if_conds(node ast.Expr, mut scope ast.Scope) {
|
|||
} else {
|
||||
return
|
||||
}
|
||||
} else if !c.check_types(right_type, expr_type) {
|
||||
} else if !c.check_types(right_type, expr_type) && left_sym.kind != .sum_type {
|
||||
expect_str := c.table.type_to_str(right_type)
|
||||
expr_str := c.table.type_to_str(expr_type)
|
||||
c.error('cannot use type `$expect_str` as type `$expr_str`', node.pos)
|
||||
|
|
|
|||
|
|
@ -162,9 +162,10 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
|
|||
c.expected_type = node.expected_type
|
||||
low_expr := expr.low
|
||||
high_expr := expr.high
|
||||
final_cond_sym := c.table.final_sym(node.cond_type)
|
||||
if low_expr is ast.IntegerLiteral {
|
||||
if high_expr is ast.IntegerLiteral
|
||||
&& (cond_type_sym.is_int() || cond_type_sym.info is ast.Enum) {
|
||||
&& (final_cond_sym.is_int() || final_cond_sym.info is ast.Enum) {
|
||||
low = low_expr.val.i64()
|
||||
high = high_expr.val.i64()
|
||||
if low > high {
|
||||
|
|
@ -174,7 +175,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
|
|||
c.error('mismatched range types', low_expr.pos)
|
||||
}
|
||||
} else if low_expr is ast.CharLiteral {
|
||||
if high_expr is ast.CharLiteral && cond_type_sym.kind in [.u8, .char, .rune] {
|
||||
if high_expr is ast.CharLiteral && final_cond_sym.kind in [.u8, .char, .rune] {
|
||||
low = low_expr.val[0]
|
||||
high = high_expr.val[0]
|
||||
if low > high {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
|||
mut got_types := []ast.Type{}
|
||||
mut expr_idxs := []int{}
|
||||
for i, expr in node.exprs {
|
||||
typ := c.expr(expr)
|
||||
mut typ := c.expr(expr)
|
||||
if typ == ast.void_type {
|
||||
c.error('`$expr` used as value', node.pos)
|
||||
}
|
||||
|
|
@ -46,6 +46,13 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
|||
expr_idxs << i
|
||||
}
|
||||
} else {
|
||||
if expr is ast.Ident {
|
||||
if expr.obj is ast.Var {
|
||||
if expr.obj.smartcasts.len > 0 {
|
||||
typ = c.unwrap_generic(expr.obj.smartcasts.last())
|
||||
}
|
||||
}
|
||||
}
|
||||
got_types << typ
|
||||
expr_idxs << i
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
vlib/v/checker/tests/array_builtin_method_args_err.vv:4:18: error: `.clone()` does not have any arguments
|
||||
2 | arr := [1, 2, 3]
|
||||
3 |
|
||||
4 | a1 := arr.clone(22)
|
||||
| ~~
|
||||
5 | println(a1)
|
||||
6 |
|
||||
vlib/v/checker/tests/array_builtin_method_args_err.vv:7:18: error: `.first()` does not have any arguments
|
||||
5 | println(a1)
|
||||
6 |
|
||||
7 | a2 := arr.first('a2')
|
||||
| ~~~~
|
||||
8 | println(a2)
|
||||
9 |
|
||||
vlib/v/checker/tests/array_builtin_method_args_err.vv:10:17: error: `.last()` does not have any arguments
|
||||
8 | println(a2)
|
||||
9 |
|
||||
10 | a3 := arr.last(1)
|
||||
| ^
|
||||
11 | println(a3)
|
||||
12 |
|
||||
vlib/v/checker/tests/array_builtin_method_args_err.vv:13:16: error: `.pop()` does not have any arguments
|
||||
11 | println(a3)
|
||||
12 |
|
||||
13 | a4 := arr.pop(2)
|
||||
| ^
|
||||
14 | println(a4)
|
||||
15 | }
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
fn main() {
|
||||
arr := [1, 2, 3]
|
||||
|
||||
a1 := arr.clone(22)
|
||||
println(a1)
|
||||
|
||||
a2 := arr.first('a2')
|
||||
println(a2)
|
||||
|
||||
a3 := arr.last(1)
|
||||
println(a3)
|
||||
|
||||
a4 := arr.pop(2)
|
||||
println(a4)
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
vlib/v/checker/tests/array_contains_args_err.vv:3:17: error: `.contains()` expected `int` argument, but got `[]int`
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:3:26: error: cannot use `[]int` as `int` in argument 1 to `.contains()`
|
||||
1 | fn main() {
|
||||
2 | arr := [0]
|
||||
3 | mut ret := [0].contains([0])
|
||||
| ~~~~~~~~~~~~~
|
||||
| ~~~
|
||||
4 | ret = [0].contains()
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:4:12: error: `.contains()` expected 1 argument, but got 0
|
||||
|
|
@ -19,17 +19,17 @@ vlib/v/checker/tests/array_contains_args_err.vv:5:18: error: `.contains()` expec
|
|||
| ~~~~~~~~~~~~~~~~~
|
||||
6 | ret = [0].contains('a')
|
||||
7 | ret = [0].contains(arr)
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:6:12: error: `.contains()` expected `int` argument, but got `string`
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:6:21: error: cannot use `string` as `int` in argument 1 to `.contains()`
|
||||
4 | ret = [0].contains()
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
6 | ret = [0].contains('a')
|
||||
| ~~~~~~~~~~~~~
|
||||
| ~~~
|
||||
7 | ret = [0].contains(arr)
|
||||
8 | println(ret)
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:7:12: error: `.contains()` expected `int` argument, but got `[]int`
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:7:21: error: cannot use `[]int` as `int` in argument 1 to `.contains()`
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
6 | ret = [0].contains('a')
|
||||
7 | ret = [0].contains(arr)
|
||||
| ~~~~~~~~~~~~~
|
||||
| ~~~
|
||||
8 | println(ret)
|
||||
9 | }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
vlib/v/checker/tests/array_index_args_err.vv:3:23: error: cannot use `[]int` as `int` in argument 1 to `.index()`
|
||||
1 | fn main() {
|
||||
2 | arr := [0]
|
||||
3 | mut ret := [0].index([0])
|
||||
| ~~~
|
||||
4 | ret = [0].index()
|
||||
5 | ret = [0, 1, 2].index(0, 1, 2)
|
||||
vlib/v/checker/tests/array_index_args_err.vv:4:12: error: `.index()` expected 1 argument, but got 0
|
||||
2 | arr := [0]
|
||||
3 | mut ret := [0].index([0])
|
||||
4 | ret = [0].index()
|
||||
| ~~~~~~~
|
||||
5 | ret = [0, 1, 2].index(0, 1, 2)
|
||||
6 | ret = [0].index('a')
|
||||
vlib/v/checker/tests/array_index_args_err.vv:5:18: error: `.index()` expected 1 argument, but got 3
|
||||
3 | mut ret := [0].index([0])
|
||||
4 | ret = [0].index()
|
||||
5 | ret = [0, 1, 2].index(0, 1, 2)
|
||||
| ~~~~~~~~~~~~~~
|
||||
6 | ret = [0].index('a')
|
||||
7 | ret = [0].index(arr)
|
||||
vlib/v/checker/tests/array_index_args_err.vv:6:18: error: cannot use `string` as `int` in argument 1 to `.index()`
|
||||
4 | ret = [0].index()
|
||||
5 | ret = [0, 1, 2].index(0, 1, 2)
|
||||
6 | ret = [0].index('a')
|
||||
| ~~~
|
||||
7 | ret = [0].index(arr)
|
||||
8 | println(ret)
|
||||
vlib/v/checker/tests/array_index_args_err.vv:7:18: error: cannot use `[]int` as `int` in argument 1 to `.index()`
|
||||
5 | ret = [0, 1, 2].index(0, 1, 2)
|
||||
6 | ret = [0].index('a')
|
||||
7 | ret = [0].index(arr)
|
||||
| ~~~
|
||||
8 | println(ret)
|
||||
9 | }
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fn main() {
|
||||
arr := [0]
|
||||
mut ret := [0].index([0])
|
||||
ret = [0].index()
|
||||
ret = [0, 1, 2].index(0, 1, 2)
|
||||
ret = [0].index('a')
|
||||
ret = [0].index(arr)
|
||||
println(ret)
|
||||
}
|
||||
|
|
@ -17,10 +17,45 @@ vlib/v/checker/tests/compare_unsigned_signed.vv:10:16: error: `u8` cannot be com
|
|||
10 | _ = u8(-1) == -1 // false!
|
||||
| ~~
|
||||
11 | _ = -1 == u16(-1) // false!
|
||||
12 | }
|
||||
12 |
|
||||
vlib/v/checker/tests/compare_unsigned_signed.vv:11:6: error: negative value cannot be compared with `u16`
|
||||
9 | // unsigned == literal
|
||||
10 | _ = u8(-1) == -1 // false!
|
||||
11 | _ = -1 == u16(-1) // false!
|
||||
| ~~
|
||||
12 | }
|
||||
12 |
|
||||
13 | // smaller unsigned == signed, OK
|
||||
vlib/v/checker/tests/compare_unsigned_signed.vv:18:12: error: `i8` cannot be compared with `u16`
|
||||
16 |
|
||||
17 | // smaller signed == unsigned, NG
|
||||
18 | _ = i8(0) == u16(0)
|
||||
| ~~
|
||||
19 | _ = i16(0) != u32(0)
|
||||
20 | _ = int(0) == u64(0)
|
||||
vlib/v/checker/tests/compare_unsigned_signed.vv:19:13: error: `i16` cannot be compared with `u32`
|
||||
17 | // smaller signed == unsigned, NG
|
||||
18 | _ = i8(0) == u16(0)
|
||||
19 | _ = i16(0) != u32(0)
|
||||
| ~~
|
||||
20 | _ = int(0) == u64(0)
|
||||
21 | _ = i32(0) == u64(0) // FIXME
|
||||
vlib/v/checker/tests/compare_unsigned_signed.vv:20:13: error: `int` cannot be compared with `u64`
|
||||
18 | _ = i8(0) == u16(0)
|
||||
19 | _ = i16(0) != u32(0)
|
||||
20 | _ = int(0) == u64(0)
|
||||
| ~~
|
||||
21 | _ = i32(0) == u64(0) // FIXME
|
||||
22 | // swap order
|
||||
vlib/v/checker/tests/compare_unsigned_signed.vv:23:13: error: `u16` cannot be compared with `i8`
|
||||
21 | _ = i32(0) == u64(0) // FIXME
|
||||
22 | // swap order
|
||||
23 | _ = u16(0) == i8(0)
|
||||
| ~~
|
||||
24 | _ = u64(0) == i16(0)
|
||||
25 | }
|
||||
vlib/v/checker/tests/compare_unsigned_signed.vv:24:13: error: `u64` cannot be compared with `i16`
|
||||
22 | // swap order
|
||||
23 | _ = u16(0) == i8(0)
|
||||
24 | _ = u64(0) == i16(0)
|
||||
| ~~
|
||||
25 | }
|
||||
|
|
|
|||
|
|
@ -9,4 +9,17 @@ fn main() {
|
|||
// unsigned == literal
|
||||
_ = u8(-1) == -1 // false!
|
||||
_ = -1 == u16(-1) // false!
|
||||
|
||||
// smaller unsigned == signed, OK
|
||||
_ = u16(-1) == int(-1)
|
||||
_ = int(-1) != u8(-1)
|
||||
|
||||
// smaller signed == unsigned, NG
|
||||
_ = i8(0) == u16(0)
|
||||
_ = i16(0) != u32(0)
|
||||
_ = int(0) == u64(0)
|
||||
_ = i32(0) == u64(0) // FIXME
|
||||
// swap order
|
||||
_ = u16(0) == i8(0)
|
||||
_ = u64(0) == i16(0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
vlib/v/checker/tests/if_match_expr.vv:8:6: error: `if` expression branch has unsupported statement (`v.ast.ForStmt`)
|
||||
6 | if true {1} else {-1} // result
|
||||
7 | } else {
|
||||
8 | for {break}
|
||||
| ^
|
||||
9 | {}
|
||||
10 | match true {true {} else {}} // statement not expression
|
||||
vlib/v/checker/tests/if_match_expr.vv:9:2: error: `if` expression branch has unsupported statement (`v.ast.Block`)
|
||||
7 | } else {
|
||||
8 | for {break}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
vlib/v/checker/tests/map_builtin_method_args_err.vv:4:16: error: `.clone()` does not have any arguments
|
||||
2 | mut m := {11: 22}
|
||||
3 |
|
||||
4 | a1 := m.clone(11)
|
||||
| ~~
|
||||
5 | println(a1)
|
||||
6 |
|
||||
vlib/v/checker/tests/map_builtin_method_args_err.vv:7:15: error: `.move()` does not have any arguments
|
||||
5 | println(a1)
|
||||
6 |
|
||||
7 | a2 := m.move(11)
|
||||
| ~~
|
||||
8 | println(a2)
|
||||
9 |
|
||||
vlib/v/checker/tests/map_builtin_method_args_err.vv:10:15: error: `.keys()` does not have any arguments
|
||||
8 | println(a2)
|
||||
9 |
|
||||
10 | a3 := m.keys('aaa')
|
||||
| ~~~~~
|
||||
11 | println(a3)
|
||||
12 | }
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fn main() {
|
||||
mut m := {11: 22}
|
||||
|
||||
a1 := m.clone(11)
|
||||
println(a1)
|
||||
|
||||
a2 := m.move(11)
|
||||
println(a2)
|
||||
|
||||
a3 := m.keys('aaa')
|
||||
println(a3)
|
||||
}
|
||||
|
|
@ -511,8 +511,13 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
|
|||
|
||||
return res
|
||||
}
|
||||
else {
|
||||
e.error('unhandled expression $expr.type_name()')
|
||||
ast.AnonFn, ast.ArrayDecompose, ast.AsCast, ast.Assoc, ast.AtExpr, ast.CTempVar,
|
||||
ast.ChanInit, ast.Comment, ast.ComptimeCall, ast.ComptimeSelector, ast.ComptimeType,
|
||||
ast.ConcatExpr, ast.DumpExpr, ast.EmptyExpr, ast.EnumVal, ast.GoExpr, ast.IfGuardExpr,
|
||||
ast.IndexExpr, ast.IsRefType, ast.Likely, ast.LockExpr, ast.MapInit, ast.MatchExpr,
|
||||
ast.NodeError, ast.None, ast.OffsetOf, ast.OrExpr, ast.RangeExpr, ast.SelectExpr,
|
||||
ast.SqlExpr, ast.TypeNode, ast.TypeOf, ast.UnsafeExpr {
|
||||
e.error('unhandled expression ${typeof(expr).name}')
|
||||
}
|
||||
}
|
||||
return empty
|
||||
|
|
|
|||
|
|
@ -1462,7 +1462,7 @@ pub fn (mut f Fmt) array_init(node ast.ArrayInit) {
|
|||
|| f.line_len + expr.pos().len > fmt.max_len[3]
|
||||
}
|
||||
}
|
||||
line_break := f.array_init_break[f.array_init_depth - 1]
|
||||
mut line_break := f.array_init_break[f.array_init_depth - 1]
|
||||
mut penalty := if line_break { 0 } else { 4 }
|
||||
if penalty > 0 {
|
||||
if i == 0
|
||||
|
|
@ -1480,14 +1480,26 @@ pub fn (mut f Fmt) array_init(node ast.ArrayInit) {
|
|||
}
|
||||
single_line_expr := expr_is_single_line(expr)
|
||||
if single_line_expr {
|
||||
estr := f.node_str(expr)
|
||||
if !is_new_line && !f.buffering && f.line_len + estr.len > fmt.max_len.last() {
|
||||
mut estr := ''
|
||||
if !is_new_line && !f.buffering && f.line_len + expr.pos().len > fmt.max_len.last() {
|
||||
if inc_indent {
|
||||
estr = f.node_str(expr)
|
||||
}
|
||||
f.writeln('')
|
||||
is_new_line = true
|
||||
if !inc_indent {
|
||||
f.indent++
|
||||
inc_indent = true
|
||||
f.write_indent()
|
||||
f.empty_line = false
|
||||
estr = f.node_str(expr)
|
||||
}
|
||||
if i == 0 {
|
||||
f.array_init_break[f.array_init_depth - 1] = true
|
||||
line_break = true
|
||||
}
|
||||
} else {
|
||||
estr = f.node_str(expr)
|
||||
}
|
||||
if !is_new_line && i > 0 {
|
||||
f.write(' ')
|
||||
|
|
@ -2315,7 +2327,11 @@ pub fn (mut f Fmt) par_expr(node ast.ParExpr) {
|
|||
f.par_level++
|
||||
f.write('(')
|
||||
}
|
||||
f.expr(node.expr)
|
||||
mut expr := node.expr
|
||||
for mut expr is ast.ParExpr {
|
||||
expr = expr.expr
|
||||
}
|
||||
f.expr(expr)
|
||||
if requires_paren {
|
||||
f.par_level--
|
||||
f.write(')')
|
||||
|
|
|
|||
|
|
@ -6,8 +6,7 @@ const (
|
|||
header: {
|
||||
'Set-Cookie': ['special-7=","']
|
||||
}
|
||||
cookies: [
|
||||
&http.Cookie{
|
||||
cookies: [&http.Cookie{
|
||||
name: 'special-7'
|
||||
value: ','
|
||||
raw: 'special-8=","'
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@ fn wrapping_tests() {
|
|||
'elit. Donec varius purus leo, vel maximus diam',
|
||||
'finibus sed. Etiam eu urna ante. Nunc quis vehicula',
|
||||
'velit. Sed at mauris et quam ornare tristique.']
|
||||
multi_level := [
|
||||
[1, 2, 3],
|
||||
[
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec varius purus leo, vel maximus diam',
|
||||
'finibus sed. Etiam eu urna ante. Nunc quis vehicula velit. Sed at mauris et quam ornare tristique.',
|
||||
],
|
||||
]
|
||||
}
|
||||
|
||||
fn array_init_without_commas() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ fn main() {
|
|||
|
||||
fn wrapping_tests() {
|
||||
my_arr := ['Lorem ipsum dolor sit amet, consectetur adipiscing', 'elit. Donec varius purus leo, vel maximus diam', 'finibus sed. Etiam eu urna ante. Nunc quis vehicula', 'velit. Sed at mauris et quam ornare tristique.']
|
||||
multi_level := [
|
||||
[1, 2, 3],
|
||||
['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec varius purus leo, vel maximus diam', 'finibus sed. Etiam eu urna ante. Nunc quis vehicula velit. Sed at mauris et quam ornare tristique.'],
|
||||
]
|
||||
}
|
||||
|
||||
fn array_init_without_commas() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
_, _ := (22 > 11), (43 > 22)
|
||||
_ := (10 + 11)
|
||||
_ := (11 * 2)
|
||||
_ := (11 * 2)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
fn main() {
|
||||
_, _ := (((22 > 11))), (43 > 22)
|
||||
_ := ((10 + 11))
|
||||
_ := ((((((11 * 2))))))
|
||||
_ := ((11 * 2))
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
|
|||
g.inside_lambda = false
|
||||
return
|
||||
}
|
||||
need_tmp_var := g.inside_call && !g.inside_struct_init
|
||||
need_tmp_var := g.inside_call && !g.inside_struct_init && node.exprs.len == 0
|
||||
mut stmt_str := ''
|
||||
mut tmp_var := ''
|
||||
if need_tmp_var {
|
||||
|
|
|
|||
|
|
@ -314,11 +314,32 @@ fn (mut g Gen) gen_assign_stmt(node_ ast.AssignStmt) {
|
|||
}
|
||||
func := right_sym.info as ast.FnType
|
||||
ret_styp := g.typ(func.func.return_type)
|
||||
g.write('$ret_styp (*${g.get_ternary_name(ident.name)}) (')
|
||||
|
||||
mut call_conv := ''
|
||||
mut msvc_call_conv := ''
|
||||
for attr in func.func.attrs {
|
||||
match attr.name {
|
||||
'callconv' {
|
||||
if g.is_cc_msvc {
|
||||
msvc_call_conv = '__$attr.arg '
|
||||
} else {
|
||||
call_conv = '$attr.arg'
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
call_conv_attribute_suffix := if call_conv.len != 0 {
|
||||
'__attribute__(($call_conv))'
|
||||
} else {
|
||||
''
|
||||
}
|
||||
|
||||
g.write('$ret_styp ($msvc_call_conv*${g.get_ternary_name(ident.name)}) (')
|
||||
def_pos := g.definitions.len
|
||||
g.fn_decl_params(func.func.params, voidptr(0), false)
|
||||
g.definitions.go_back(g.definitions.len - def_pos)
|
||||
g.write(')')
|
||||
g.write(')$call_conv_attribute_suffix')
|
||||
} else {
|
||||
if is_decl {
|
||||
if is_inside_ternary {
|
||||
|
|
|
|||
|
|
@ -3286,7 +3286,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
|||
if field_sym.kind == .sum_type {
|
||||
g.write('*')
|
||||
}
|
||||
cast_sym := g.table.sym(typ)
|
||||
cast_sym := g.table.sym(g.unwrap_generic(typ))
|
||||
if i != 0 {
|
||||
dot := if field.typ.is_ptr() { '->' } else { '.' }
|
||||
sum_type_deref_field += ')$dot'
|
||||
|
|
@ -5185,11 +5185,13 @@ fn (mut g Gen) enum_val(node ast.EnumVal) {
|
|||
// g.write('${it.mod}${it.enum_name}_$it.val')
|
||||
// g.enum_expr(node)
|
||||
styp := g.typ(g.table.unaliased_type(node.typ))
|
||||
if node.typ.is_number() {
|
||||
// && g.inside_switch
|
||||
if g.pref.translated && node.typ.is_number() {
|
||||
// Mostly in translated code, when C enums are used as ints in switches
|
||||
// g.write('/*enum val is_number $node.mod styp=$styp*/')
|
||||
g.write('/*enum val is_number $node.mod styp=$styp*/_const_main__$node.val')
|
||||
} else {
|
||||
g.write('${styp}__$node.val')
|
||||
}
|
||||
g.write('${styp}__$node.val')
|
||||
}
|
||||
|
||||
fn (mut g Gen) as_cast(node ast.AsCast) {
|
||||
|
|
|
|||
|
|
@ -379,7 +379,10 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
|||
defer {
|
||||
g.tmp_count = ctmp
|
||||
}
|
||||
prev_inside_ternary := g.inside_ternary
|
||||
g.inside_ternary = 0
|
||||
g.stmts(node.stmts)
|
||||
g.inside_ternary = prev_inside_ternary
|
||||
if node.is_noreturn {
|
||||
g.writeln('\twhile(1);')
|
||||
}
|
||||
|
|
@ -637,11 +640,12 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||
// see my comment in parser near anon_fn
|
||||
if node.left is ast.AnonFn {
|
||||
g.expr(node.left)
|
||||
}
|
||||
if node.left is ast.IndexExpr && node.name == '' {
|
||||
} else if node.left is ast.IndexExpr && node.name == '' {
|
||||
g.is_fn_index_call = true
|
||||
g.expr(node.left)
|
||||
g.is_fn_index_call = false
|
||||
} else if node.left is ast.CallExpr && node.name == '' {
|
||||
g.expr(node.left)
|
||||
}
|
||||
if node.should_be_skipped {
|
||||
return
|
||||
|
|
@ -941,7 +945,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
g.gen_expr_to_string(node.left, rec_type)
|
||||
return
|
||||
} else if node.left.obj.smartcasts.len > 0 {
|
||||
rec_type = node.left.obj.smartcasts.last()
|
||||
rec_type = g.unwrap_generic(node.left.obj.smartcasts.last())
|
||||
cast_sym := g.table.sym(rec_type)
|
||||
if cast_sym.info is ast.Aggregate {
|
||||
rec_type = cast_sym.info.types[g.aggregate_type_idx]
|
||||
|
|
@ -1331,7 +1335,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
if expr.obj is ast.Var {
|
||||
typ = expr.obj.typ
|
||||
if expr.obj.smartcasts.len > 0 {
|
||||
typ = expr.obj.smartcasts.last()
|
||||
typ = g.unwrap_generic(expr.obj.smartcasts.last())
|
||||
cast_sym := g.table.sym(typ)
|
||||
if cast_sym.info is ast.Aggregate {
|
||||
typ = cast_sym.info.types[g.aggregate_type_idx]
|
||||
|
|
@ -2040,6 +2044,12 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as
|
|||
g.expr(arg.expr)
|
||||
g.write('->val')
|
||||
return
|
||||
} else if arg.expr is ast.ArrayInit {
|
||||
if arg.expr.is_fixed {
|
||||
if !arg.expr.has_it {
|
||||
g.write('(${g.typ(arg.expr.typ)})')
|
||||
}
|
||||
}
|
||||
}
|
||||
g.expr_with_cast(arg.expr, arg_typ, expected_type)
|
||||
if needs_closing {
|
||||
|
|
|
|||
|
|
@ -299,14 +299,15 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
|
|||
} else {
|
||||
node.cond
|
||||
}
|
||||
field_accessor := if node.cond_type.is_ptr() { '->' } else { '.' }
|
||||
i := if node.key_var in ['', '_'] { g.new_tmp_var() } else { node.key_var }
|
||||
g.write('for (int $i = 0; $i < ')
|
||||
g.expr(cond)
|
||||
g.writeln('.len; ++$i) {')
|
||||
g.writeln('${field_accessor}len; ++$i) {')
|
||||
if node.val_var != '_' {
|
||||
g.write('\tbyte ${c_name(node.val_var)} = ')
|
||||
g.write('\tu8 ${c_name(node.val_var)} = ')
|
||||
g.expr(cond)
|
||||
g.writeln('.str[$i];')
|
||||
g.writeln('${field_accessor}str[$i];')
|
||||
}
|
||||
} else if node.kind == .struct_ {
|
||||
cond_type_sym := g.table.sym(node.cond_type)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ fn (mut g Gen) need_tmp_var_in_if(node ast.IfExpr) bool {
|
|||
if is_noreturn_callexpr(stmt.expr) {
|
||||
return true
|
||||
}
|
||||
if stmt.expr is ast.MatchExpr {
|
||||
return true
|
||||
}
|
||||
if stmt.expr is ast.CallExpr {
|
||||
if stmt.expr.is_method {
|
||||
left_sym := g.table.sym(stmt.expr.receiver_type)
|
||||
|
|
|
|||
|
|
@ -708,7 +708,8 @@ fn (mut g Gen) infix_expr_left_shift_op(node ast.InfixExpr) {
|
|||
g.write(', _MOV(($elem_type_str[]){ ')
|
||||
}
|
||||
// if g.autofree
|
||||
needs_clone := array_info.elem_type.idx() == ast.string_type_idx && !g.is_builtin_mod
|
||||
needs_clone := !g.is_builtin_mod && array_info.elem_type.idx() == ast.string_type_idx
|
||||
&& array_info.elem_type.nr_muls() == 0
|
||||
if needs_clone {
|
||||
g.write('string_clone(')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
|||
}
|
||||
g.inside_match_optional = true
|
||||
}
|
||||
if node.cond in [ast.Ident, ast.SelectorExpr, ast.IntegerLiteral, ast.StringLiteral,
|
||||
ast.FloatLiteral] {
|
||||
if node.cond in [ast.Ident, ast.SelectorExpr, ast.IntegerLiteral, ast.StringLiteral, ast.FloatLiteral] {
|
||||
cond_var = g.expr_string(node.cond)
|
||||
} else {
|
||||
line := if is_expr {
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ fn (mut g Gen) str_val(node ast.StringInterLiteral, i int) {
|
|||
if g.comptime_var_type_map.len > 0 || g.comptime_for_method.len > 0 {
|
||||
exp_typ = expr.obj.typ
|
||||
} else if expr.obj.smartcasts.len > 0 {
|
||||
exp_typ = expr.obj.smartcasts.last()
|
||||
exp_typ = g.unwrap_generic(expr.obj.smartcasts.last())
|
||||
cast_sym := g.table.sym(exp_typ)
|
||||
if cast_sym.info is ast.Aggregate {
|
||||
exp_typ = cast_sym.info.types[g.aggregate_type_idx]
|
||||
|
|
|
|||
|
|
@ -2426,8 +2426,8 @@ fn (mut g JsGen) match_expr(node ast.MatchExpr) {
|
|||
g.inside_ternary = true
|
||||
}
|
||||
|
||||
if node.cond in [ast.Ident, ast.SelectorExpr, ast.IntegerLiteral, ast.StringLiteral,
|
||||
ast.FloatLiteral, ast.CallExpr, ast.EnumVal] {
|
||||
if node.cond in [ast.Ident, ast.SelectorExpr, ast.IntegerLiteral, ast.StringLiteral, ast.FloatLiteral,
|
||||
ast.CallExpr, ast.EnumVal] {
|
||||
cond_var = CondExpr{node.cond}
|
||||
} else {
|
||||
s := g.new_tmp_var()
|
||||
|
|
|
|||
|
|
@ -783,9 +783,10 @@ fn (mut p Parser) fn_args() ([]ast.Param, bool, bool) {
|
|||
} else {
|
||||
p.tok.lit
|
||||
}
|
||||
is_generic_type := p.tok.kind == .name && p.tok.lit.len == 1 && p.tok.lit[0].is_capital()
|
||||
|
||||
types_only := p.tok.kind in [.amp, .ellipsis, .key_fn, .lsbr]
|
||||
|| (p.peek_tok.kind == .comma && p.table.known_type(argname))
|
||||
|| (p.peek_tok.kind == .comma && (p.table.known_type(argname) || is_generic_type))
|
||||
|| p.peek_tok.kind == .dot || p.peek_tok.kind == .rpar
|
||||
|| (p.tok.kind == .key_mut && (p.peek_token(2).kind == .comma
|
||||
|| p.peek_token(2).kind == .rpar || (p.peek_tok.kind == .name
|
||||
|
|
|
|||
|
|
@ -791,7 +791,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
|||
spos := p.tok.pos()
|
||||
name := p.check_name()
|
||||
if name in p.label_names {
|
||||
p.error_with_pos('duplicate label `$name`', spos)
|
||||
return p.error_with_pos('duplicate label `$name`', spos)
|
||||
}
|
||||
p.label_names << name
|
||||
p.next()
|
||||
|
|
@ -812,7 +812,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
|
|||
return stmt
|
||||
}
|
||||
else {
|
||||
p.error_with_pos('unknown kind of For statement', for_pos)
|
||||
return p.error_with_pos('unknown kind of For statement', for_pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2327,6 +2327,18 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
|||
p.error_with_pos('unexpected $p.prev_tok', p.prev_tok.pos())
|
||||
}
|
||||
node = p.call_expr(language, mod)
|
||||
if p.tok.kind == .lpar && p.prev_tok.line_nr == p.tok.line_nr {
|
||||
p.next()
|
||||
pos := p.tok.pos()
|
||||
args := p.call_args()
|
||||
p.check(.rpar)
|
||||
node = ast.CallExpr{
|
||||
left: node
|
||||
args: args
|
||||
pos: pos
|
||||
scope: p.scope
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (p.peek_tok.kind == .lcbr || (p.peek_tok.kind == .lt && lit0_is_capital))
|
||||
&& (!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital))
|
||||
|
|
|
|||
|
|
@ -256,30 +256,27 @@ fn vweb_tmpl_${fn_name}() string {
|
|||
|
||||
match state {
|
||||
.html {
|
||||
if line.starts_with('span.') && line.ends_with('{') {
|
||||
line_t := line.trim_space()
|
||||
if line_t.starts_with('span.') && line.ends_with('{') {
|
||||
// `span.header {` => `<span class='header'>`
|
||||
class := line.find_between('span.', '{').trim_space()
|
||||
source.writeln('<span class="$class">')
|
||||
in_span = true
|
||||
continue
|
||||
}
|
||||
if line.trim_space().starts_with('.') && line.ends_with('{') {
|
||||
} else if line_t.starts_with('.') && line.ends_with('{') {
|
||||
// `.header {` => `<div class='header'>`
|
||||
class := line.find_between('.', '{').trim_space()
|
||||
trimmed := line.trim_space()
|
||||
source.write_string(strings.repeat(`\t`, line.len - trimmed.len)) // add the necessary indent to keep <div><div><div> code clean
|
||||
source.writeln('<div class="$class">')
|
||||
continue
|
||||
}
|
||||
if line.starts_with('#') && line.ends_with('{') {
|
||||
} else if line_t.starts_with('#') && line.ends_with('{') {
|
||||
// `#header {` => `<div id='header'>`
|
||||
class := line.find_between('#', '{').trim_space()
|
||||
source.writeln('<div id="$class">')
|
||||
continue
|
||||
}
|
||||
if line.trim_space() == '}' {
|
||||
trimmed := line.trim_space()
|
||||
source.write_string(strings.repeat(`\t`, line.len - trimmed.len)) // add the necessary indent to keep <div><div><div> code clean
|
||||
} else if line_t == '}' {
|
||||
source.write_string(strings.repeat(`\t`, line.len - line_t.len)) // add the necessary indent to keep <div><div><div> code clean
|
||||
if in_span {
|
||||
source.writeln('</span>')
|
||||
in_span = false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
fn foofun(op rune) fn () string {
|
||||
return match op {
|
||||
`1` {
|
||||
fn () string {
|
||||
return '1 passed'
|
||||
}
|
||||
}
|
||||
`2` {
|
||||
fn () string {
|
||||
return '2 passed'
|
||||
}
|
||||
}
|
||||
else {
|
||||
fn () string {
|
||||
return 'Nor 1 or 2 passed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_anon_fn_decl_inside_ternary() {
|
||||
a := foofun(`1`)
|
||||
println(a())
|
||||
assert a() == '1 passed'
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
fn foofun1(op string) fn () string {
|
||||
return fn () string {
|
||||
return 'x passed'
|
||||
}
|
||||
}
|
||||
|
||||
fn foofun2(op string) fn () int {
|
||||
return fn () int {
|
||||
return 22
|
||||
}
|
||||
}
|
||||
|
||||
fn test_fn_call_using_anon_fn_call_arg() {
|
||||
println(main.foofun1('1')())
|
||||
assert main.foofun1('1')() == 'x passed'
|
||||
|
||||
println(main.foofun2('1')())
|
||||
assert main.foofun2('1')() == 22
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
fn show_array_of_u8(data []u8) string {
|
||||
println(data)
|
||||
return '$data'
|
||||
}
|
||||
|
||||
struct Foo {}
|
||||
|
||||
fn (f Foo) show_array_of_u8(data []u8) string {
|
||||
println(data)
|
||||
return '$data'
|
||||
}
|
||||
|
||||
fn test_fn_with_array_of_aliases_argument() {
|
||||
a := [byte(1), 2, 3]
|
||||
|
||||
s1 := show_array_of_u8(a)
|
||||
println(s1)
|
||||
assert s1 == '[0x01, 0x02, 0x03]'
|
||||
|
||||
foo := Foo{}
|
||||
s2 := foo.show_array_of_u8(a)
|
||||
println(s2)
|
||||
assert s2 == '[0x01, 0x02, 0x03]'
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
interface Any {}
|
||||
|
||||
struct ConcreteA {
|
||||
a int
|
||||
}
|
||||
|
||||
struct ConcreteB {
|
||||
b int
|
||||
}
|
||||
|
||||
struct Container {
|
||||
concrete_a Any
|
||||
concrete_b Any
|
||||
}
|
||||
|
||||
fn cast_struct<T>(any_struct Any) &T {
|
||||
if any_struct is T {
|
||||
return any_struct
|
||||
}
|
||||
panic('cannot cast')
|
||||
}
|
||||
|
||||
fn test_generic_empty_interface_to_multi_struct() {
|
||||
concrete_a := cast_struct<ConcreteA>(ConcreteA{12345})
|
||||
concrete_b := cast_struct<ConcreteB>(ConcreteB{54321})
|
||||
println(concrete_a.a)
|
||||
println(concrete_b.b)
|
||||
assert concrete_a.a == 12345
|
||||
assert concrete_b.b == 54321
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fn test_generics_anon_fn_decl_with_type_only_arg() {
|
||||
ret := func_b<int>(11, 22, add)
|
||||
println(ret)
|
||||
assert ret == 33
|
||||
}
|
||||
|
||||
fn add(a int, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
fn func_b<T>(x T, y T, f fn (T, T) T) T {
|
||||
return f(x, y)
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// vtest retry: 3
|
||||
|
||||
fn sum1(a int, b int) int {
|
||||
sum_func1 := fn (a int, b int) int {
|
||||
return a + b
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
fn test_if_expr_with_nested_match_expr() {
|
||||
a := if true {
|
||||
match `a` {
|
||||
`a` { 0 }
|
||||
else { 1 }
|
||||
}
|
||||
} else {
|
||||
3
|
||||
}
|
||||
println(a)
|
||||
assert a == 0
|
||||
}
|
||||
|
|
@ -42,9 +42,9 @@ fn test_cmp_u32_and_signed() {
|
|||
|
||||
fn test_cmp_signed_and_u64() {
|
||||
// ==
|
||||
assert int(1) == u64(1)
|
||||
// assert int(1) == u64(1)
|
||||
// !=
|
||||
assert int(1) != u64(2)
|
||||
// assert int(1) != u64(2)
|
||||
// >
|
||||
assert !(int(1) > u64(1))
|
||||
assert int(1) > u64(0)
|
||||
|
|
@ -63,9 +63,9 @@ fn test_cmp_signed_and_u64() {
|
|||
|
||||
fn test_cmp_u64_and_signed() {
|
||||
// ==
|
||||
assert u64(1) == int(1)
|
||||
// assert u64(1) == int(1)
|
||||
// !=
|
||||
assert u64(2) != int(1)
|
||||
// assert u64(2) != int(1)
|
||||
// >
|
||||
assert !(u64(1) > int(1))
|
||||
assert u64(1) > int(0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
97
|
||||
98
|
||||
99
|
||||
abc
|
||||
23
|
||||
77
|
||||
abc
|
||||
> k: abc | v: xyz
|
||||
> k: def | v: jkl
|
||||
abc
|
||||
abc
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
interface Any {}
|
||||
|
||||
fn abc(a Any) {
|
||||
if a is string {
|
||||
for x in a {
|
||||
println(x)
|
||||
}
|
||||
}
|
||||
if a is []u8 {
|
||||
for x in a {
|
||||
println(x)
|
||||
}
|
||||
}
|
||||
if a is map[string]string {
|
||||
for k, v in a {
|
||||
println('> k: $k | v: $v')
|
||||
}
|
||||
}
|
||||
println(@FN)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
abc('abc')
|
||||
abc([u8(23), 77])
|
||||
abc({
|
||||
'abc': 'xyz'
|
||||
'def': 'jkl'
|
||||
})
|
||||
abc(123)
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
[[1, 2], [3, 3]]
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
a := [[1, 2]!, [3, 3]!]!
|
||||
println([[a[0][0], a[0][1]]!, [a[1][0], a[1][1]]!]!)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fn test_match_aliases() {
|
||||
a := byte(97)
|
||||
ret := match a {
|
||||
`0`...`9`, `a`...`f` { 'OK' }
|
||||
else { 'NOT OK' }
|
||||
}
|
||||
println(ret)
|
||||
assert ret == 'OK'
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
fn test_match_with_for_in_loop() {
|
||||
a := 101
|
||||
b := match a {
|
||||
101 {
|
||||
mut aa := []int{}
|
||||
for i in 0 .. 3 {
|
||||
aa << i
|
||||
}
|
||||
aa
|
||||
}
|
||||
else {
|
||||
[0]
|
||||
}
|
||||
}
|
||||
println(b)
|
||||
assert b == [0, 1, 2]
|
||||
}
|
||||
|
||||
fn test_match_with_for_c_loop() {
|
||||
a := 101
|
||||
b := match a {
|
||||
101 {
|
||||
mut aa := []int{}
|
||||
for i := 0; i < 3; i++ {
|
||||
aa << i
|
||||
}
|
||||
aa
|
||||
}
|
||||
else {
|
||||
[0]
|
||||
}
|
||||
}
|
||||
println(b)
|
||||
assert b == [0, 1, 2]
|
||||
}
|
||||
|
||||
fn test_match_with_for_loop() {
|
||||
a := 101
|
||||
b := match a {
|
||||
101 {
|
||||
mut aa := []int{}
|
||||
mut i := 0
|
||||
for {
|
||||
aa << i
|
||||
i++
|
||||
if i == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
aa
|
||||
}
|
||||
else {
|
||||
[0]
|
||||
}
|
||||
}
|
||||
println(b)
|
||||
assert b == [0, 1, 2]
|
||||
}
|
||||
|
|
@ -58,13 +58,13 @@ fn test_shift_operators() {
|
|||
assert e == a
|
||||
mut e3 := u64(1)
|
||||
e3 <<= u32(i)
|
||||
assert e3 == b
|
||||
assert e3 == u64(b)
|
||||
e3 >>= u32(i)
|
||||
assert e == a
|
||||
e3 <<= u64(i)
|
||||
assert e3 == b
|
||||
assert e3 == u64(b)
|
||||
e3 >>= u64(i)
|
||||
assert e3 == a
|
||||
assert e3 == u64(a)
|
||||
// Test shifts with custom int types
|
||||
x := MyInt(2)
|
||||
assert x << 2 == 8
|
||||
|
|
|
|||
|
|
@ -1,7 +1,18 @@
|
|||
fn test_str_array_of_reference() {
|
||||
fn test_creating_an_array_of_string_reference() {
|
||||
names := ['John', 'Paul', 'George', 'Ringo']
|
||||
a := unsafe { [&names[0], &names[1]] }
|
||||
println(a[0])
|
||||
println(a)
|
||||
assert '$a' == "[&'John', &'Paul']"
|
||||
assert typeof(a[0]).name == '&string'
|
||||
}
|
||||
|
||||
fn test_pushing_to_an_array_of_string_references() {
|
||||
mut a := []&string{}
|
||||
v1 := 'abc'
|
||||
v2 := 'def'
|
||||
a << &v1
|
||||
a << &v2
|
||||
assert *(a[0]) == 'abc'
|
||||
assert *(a[1]) == 'def'
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue