Merge branch 'master' into unsigned-eq

pull/13967/head
Delyan Angelov 2022-04-11 13:36:31 +03:00 committed by GitHub
commit f8ae042eb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 531 additions and 238 deletions

View File

@ -306,13 +306,15 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
mut run_js := false mut run_js := false
is_fmt := ts.vargs.contains('fmt') is_fmt := ts.vargs.contains('fmt')
is_vet := ts.vargs.contains('vet')
produces_file_output := !(is_fmt || is_vet)
if relative_file.ends_with('js.v') { if relative_file.ends_with('js.v') {
if !is_fmt { if produces_file_output {
cmd_options << ' -b js' cmd_options << ' -b js'
}
run_js = true run_js = true
} }
}
if relative_file.contains('global') && !is_fmt { if relative_file.contains('global') && !is_fmt {
cmd_options << ' -enable-globals' cmd_options << ' -enable-globals'
@ -333,13 +335,13 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
fname.replace('.v', '') fname.replace('.v', '')
} }
generated_binary_fpath := os.join_path_single(tmpd, generated_binary_fname) generated_binary_fpath := os.join_path_single(tmpd, generated_binary_fname)
if produces_file_output {
if os.exists(generated_binary_fpath) { if os.exists(generated_binary_fpath) {
if ts.rm_binaries { if ts.rm_binaries {
os.rm(generated_binary_fpath) or {} os.rm(generated_binary_fpath) or {}
} }
} }
if !ts.vargs.contains('fmt') {
cmd_options << ' -o ${os.quoted_path(generated_binary_fpath)}' cmd_options << ' -o ${os.quoted_path(generated_binary_fpath)}'
} }
cmd := '${os.quoted_path(ts.vexe)} ' + cmd_options.join(' ') + ' ${os.quoted_path(file)}' cmd := '${os.quoted_path(ts.vexe)} ' + cmd_options.join(' ') + ' ${os.quoted_path(file)}'
@ -421,11 +423,9 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
} }
} }
} }
if os.exists(generated_binary_fpath) { if produces_file_output && os.exists(generated_binary_fpath) && ts.rm_binaries {
if ts.rm_binaries {
os.rm(generated_binary_fpath) or {} os.rm(generated_binary_fpath) or {}
} }
}
return pool.no_result return pool.no_result
} }

View File

@ -247,13 +247,9 @@ fn (mut foptions FormatOptions) post_process_file(file string, formatted_file_pa
if !is_formatted_different { if !is_formatted_different {
return return
} }
x := diff.color_compare_files(foptions.find_diff_cmd(), file, formatted_file_path)
if x.len != 0 {
println("$file is not vfmt'ed") println("$file is not vfmt'ed")
return error('') return error('')
} }
return
}
if foptions.is_c { if foptions.is_c {
if is_formatted_different { if is_formatted_different {
eprintln('File is not formatted: $file') eprintln('File is not formatted: $file')

View File

@ -87,6 +87,12 @@ fn main() {
module_names = manifest.dependencies module_names = manifest.dependencies
} }
mut source := Source.vpm mut source := Source.vpm
if '--once' in options {
module_names = vpm_once_filter(module_names)
if module_names.len == 0 {
return
}
}
if '--git' in options { if '--git' in options {
source = Source.git source = Source.git
} }
@ -327,6 +333,17 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
} }
} }
fn vpm_once_filter(module_names []string) []string {
installed_modules := get_installed_modules()
mut toinstall := []string{}
for mn in module_names {
if mn !in installed_modules {
toinstall << mn
}
}
return toinstall
}
fn vpm_install(module_names []string, source Source) { fn vpm_install(module_names []string, source Source) {
if settings.is_help { if settings.is_help {
vhelp.show_topic('install') vhelp.show_topic('install')
@ -336,17 +353,18 @@ fn vpm_install(module_names []string, source Source) {
println('´v install´ requires *at least one* module name.') println('´v install´ requires *at least one* module name.')
exit(2) exit(2)
} }
match source {
if source == .vpm { .vpm {
vpm_install_from_vpm(module_names) vpm_install_from_vpm(module_names)
} }
if source == .git { .git {
vpm_install_from_vcs(module_names, 'git') vpm_install_from_vcs(module_names, 'git')
} }
if source == .hg { .hg {
vpm_install_from_vcs(module_names, 'hg') vpm_install_from_vcs(module_names, 'hg')
} }
} }
}
fn vpm_update(m []string) { fn vpm_update(m []string) {
mut module_names := m.clone() mut module_names := m.clone()
@ -445,12 +463,11 @@ fn vpm_outdated() {
fn vpm_list() { fn vpm_list() {
module_names := get_installed_modules() module_names := get_installed_modules()
if module_names.len == 0 { if module_names.len == 0 {
println('You have no modules installed.') eprintln('You have no modules installed.')
exit(0) exit(0)
} }
println('Installed modules:')
for mod in module_names { for mod in module_names {
println(' $mod') println(mod)
} }
} }

View File

@ -8,6 +8,7 @@ Options:
--vpm - [Default] Install from vpm --vpm - [Default] Install from vpm
--git - Install from git repository url --git - Install from git repository url
--hg - Install from mercurial repository url --hg - Install from mercurial repository url
--once - Only install the module if it was not previously installed
-help - Show usage info. -help - Show usage info.
-v - Print more details about the performed operation. -v - Print more details about the performed operation.
-server-url - When doing network operations, use this vpm server. Can be given multiple times. -server-url - When doing network operations, use this vpm server. Can be given multiple times.

View File

@ -26,6 +26,8 @@ git clone https://github.com/vlang/v
cd v cd v
make make
``` ```
See [here](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Linux-and-macOS)
for how to install the development tools.
### Windows: ### Windows:
You need `git`, and a C compiler like `tcc`, `gcc`, `clang` or `msvc`: You need `git`, and a C compiler like `tcc`, `gcc`, `clang` or `msvc`:
@ -38,6 +40,9 @@ NB: You can also pass one of `-gcc`, `-msvc`, `-clang` to `make.bat` instead,
if you do prefer to use a different C compiler, but -tcc is small, fast, and if you do prefer to use a different C compiler, but -tcc is small, fast, and
easy to install (V will download a prebuilt binary automatically). easy to install (V will download a prebuilt binary automatically).
For C compiler downloads and more info, see
[here](https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows).
It is recommended to add this folder to the PATH of your environment variables. It is recommended to add this folder to the PATH of your environment variables.
This can be done with the command `v.exe symlink`. This can be done with the command `v.exe symlink`.
@ -4601,13 +4606,19 @@ v install ui
Modules can be installed directly from git or mercurial repositories. Modules can be installed directly from git or mercurial repositories.
```powershell ```powershell
v install [--git|--hg] [url] v install [--once] [--git|--hg] [url]
``` ```
**Example:** **Example:**
```powershell ```powershell
v install --git https://github.com/vlang/markdown v install --git https://github.com/vlang/markdown
``` ```
Sometimes you may want to install the dependencies **ONLY** if those are not installed:
```
v install --once [module]
```
Removing a module with v: Removing a module with v:
```powershell ```powershell

View File

@ -30,13 +30,10 @@ fn main() {
println('failed to fetch data from /v0/topstories.json') println('failed to fetch data from /v0/topstories.json')
return return
} }
mut ids := json.decode([]int, resp.text) or { ids := json.decode([]int, resp.text) or {
println('failed to decode topstories.json') println('failed to decode topstories.json')
return return
} }#[0..10]
if ids.len > 10 {
ids = ids[0..10]
}
mut fetcher_pool := pool.new_pool_processor( mut fetcher_pool := pool.new_pool_processor(
callback: worker_fetch callback: worker_fetch
) )

View File

@ -17,6 +17,8 @@ fn main() {
} }
title := 'Sokol Drawing Template' title := 'Sokol Drawing Template'
desc := sapp.Desc{ desc := sapp.Desc{
width: 640
height: 480
user_data: state user_data: state
init_userdata_cb: init init_userdata_cb: init
frame_userdata_cb: frame frame_userdata_cb: frame
@ -49,9 +51,9 @@ fn draw() {
sgl.matrix_mode_projection() sgl.matrix_mode_projection()
sgl.ortho(0.0, f32(sapp.width()), f32(sapp.height()), 0.0, -1.0, 1.0) sgl.ortho(0.0, f32(sapp.width()), f32(sapp.height()), 0.0, -1.0, 1.0)
sgl.c4b(255, 0, 0, 128) sgl.c4b(255, 0, 0, 128)
draw_hollow_rect(10, 10, 100, 30) draw_hollow_rect(220, 140, 200, 200)
sgl.c4b(25, 150, 0, 128) sgl.c4b(25, 150, 255, 128)
draw_filled_rect(10, 150, 80, 40) draw_filled_rect(270, 190, 100, 100)
// line(0, 0, 500, 500) // line(0, 0, 500, 500)
} }

View File

@ -293,3 +293,10 @@ fn test_can_copy_bits() {
// map not copyable // map not copyable
assert !can_copy_bits<map[string]int>() assert !can_copy_bits<map[string]int>()
} }
type Str = string
fn test_alias_string_contains() {
names := [Str('')]
assert (Str('') in names) == true
}

View File

@ -330,7 +330,7 @@ fn (mut cb Clipboard) start_listener() {
property: xsre.property property: xsre.property
} }
if !cb.transmit_selection(&xse) { if !cb.transmit_selection(&xse) {
xse.property = new_atom(0) xse.property = Atom(0)
} }
C.XSendEvent(cb.display, xse.requestor, 0, C.PropertyChangeMask, voidptr(&xse)) C.XSendEvent(cb.display, xse.requestor, 0, C.PropertyChangeMask, voidptr(&xse))
C.XFlush(cb.display) C.XFlush(cb.display)
@ -479,10 +479,6 @@ fn (cb &Clipboard) get_supported_targets() []Atom {
return cb.get_atoms(AtomType.utf8_string, .xa_string, .text, .text_plain, .text_html) return cb.get_atoms(AtomType.utf8_string, .xa_string, .text, .text_plain, .text_html)
} }
fn new_atom(value int) &Atom {
return unsafe { &Atom(&u64(u64(value))) }
}
fn create_xwindow(display &C.Display) Window { fn create_xwindow(display &C.Display) Window {
n := C.DefaultScreen(display) n := C.DefaultScreen(display)
return C.XCreateSimpleWindow(display, C.RootWindow(display, n), 0, 0, 1, 1, 0, C.BlackPixel(display, return C.XCreateSimpleWindow(display, C.RootWindow(display, n), 0, 0, 1, 1, 0, C.BlackPixel(display,

View File

@ -24,25 +24,34 @@ pub type Context = C.FONScontext
pub const ( pub const (
// TODO: fontstash.used_import is used to keep v from warning about unused imports // TODO: fontstash.used_import is used to keep v from warning about unused imports
used_import = 1 used_import = 1
invalid = C.FONS_INVALID // -1
) )
// Contructor and destructor. // create_internal returns a fontstash Context allocated on the heap.
//
// See also: delete_internal
[inline] [inline]
pub fn create_internal(params &C.FONSparams) &Context { pub fn create_internal(params &C.FONSparams) &Context {
return C.fonsCreateInternal(params) return C.fonsCreateInternal(params)
} }
// delete_internal deletes and free memory of `s` fontstash Context.
//
// See also: create_internal
[inline] [inline]
pub fn delete_internal(s &Context) { pub fn delete_internal(s &Context) {
C.fonsDeleteInternal(s) C.fonsDeleteInternal(s)
} }
// set_error_callback sets `callback` as a function to be called if fontstash
// encounter any errors. `uptr` can be used to pass custom userdata.
[inline] [inline]
pub fn (s &Context) set_error_callback(callback fn (voidptr, int, int), uptr voidptr) { pub fn (s &Context) set_error_callback(callback fn (voidptr, int, int), uptr voidptr) {
C.fonsSetErrorCallback(s, callback, uptr) C.fonsSetErrorCallback(s, callback, uptr)
} }
// Returns current atlas size. // get_atlas_size returns the current size of the texture atlas which
// the font is rendered to.
[inline] [inline]
pub fn (s &Context) get_atlas_size() (int, int) { pub fn (s &Context) get_atlas_size() (int, int) {
mut width := 0 mut width := 0
@ -51,126 +60,203 @@ pub fn (s &Context) get_atlas_size() (int, int) {
return width, height return width, height
} }
// Expands the atlas size. // expand_atlas expands the font texture atlas size to `width` x `height`.
[inline] [inline]
pub fn (s &Context) expand_atlas(width int, height int) int { pub fn (s &Context) expand_atlas(width int, height int) int {
return C.fonsExpandAtlas(s, width, height) return C.fonsExpandAtlas(s, width, height)
} }
// Resets the whole stash. // reset_atlas resets `width` x `height` of the font texture atlas.
[inline] [inline]
pub fn (s &Context) reset_atlas(width int, height int) int { pub fn (s &Context) reset_atlas(width int, height int) int {
return C.fonsResetAtlas(s, width, height) return C.fonsResetAtlas(s, width, height)
} }
// Add fonts // get_font_by_name returns the id of the font with `name` or
// `fontstash.invalid` if no font with `name` could be found.
[inline] [inline]
pub fn (s &Context) get_font_by_name(name string) int { pub fn (s &Context) get_font_by_name(name string) int {
return C.fonsGetFontByName(s, &char(name.str)) return C.fonsGetFontByName(s, &char(name.str))
} }
// add_fallback_font adds a fallback font to the `base` font id in the Context.
// `fallback` is expected to be the id of a previous, successfully, added font.
// add_fallback_font returns `1` on success, `0` otherwise.
[inline] [inline]
pub fn (s &Context) add_fallback_font(base int, fallback int) int { pub fn (s &Context) add_fallback_font(base int, fallback int) int {
return C.fonsAddFallbackFont(s, base, fallback) return C.fonsAddFallbackFont(s, base, fallback)
} }
// add_font_mem adds the font data located in memory to the Context.
// `name` is the human readable name for the font.
// `free_data` indicates if `data` should be freed after the font is added.
// The function returns the id of the font on success, `fontstash.invalid` otherwise.
[inline] [inline]
pub fn (s &Context) add_font_mem(name string, data []byte, free_data bool) int { pub fn (s &Context) add_font_mem(name string, data []byte, free_data bool) int {
return C.fonsAddFontMem(s, &char(name.str), data.data, data.len, int(free_data)) return C.fonsAddFontMem(s, &char(name.str), data.data, data.len, int(free_data))
} }
// State handling // push_state pushes a new state on the state stack.
// A state holds the current attributes of the rendering,
// attributes are things like color, size, the font in use, blur effect etc.
//
// See also: pop_state
// See also: clear_state
// See also: set_size
// See also: set_color
// See also: set_spacing
// See also: set_blur
// See also: set_align
// See also: set_font
[inline] [inline]
pub fn (s &Context) push_state() { pub fn (s &Context) push_state() {
C.fonsPushState(s) C.fonsPushState(s)
} }
// pop_state pops the current state from the state stack.
//
// See also: push_state
// See also: clear_state
[inline] [inline]
pub fn (s &Context) pop_state() { pub fn (s &Context) pop_state() {
C.fonsPopState(s) C.fonsPopState(s)
} }
// clear_state clears the current state.
//
// See also: push_state
// See also: pop_state
[inline] [inline]
pub fn (s &Context) clear_state() { pub fn (s &Context) clear_state() {
C.fonsClearState(s) C.fonsClearState(s)
} }
// State setting // set_size sets the font size to `size` on the active state.
//
// See also: push_state
// See also: pop_state
// See also: clear_state
[inline] [inline]
pub fn (s &Context) set_size(size f32) { pub fn (s &Context) set_size(size f32) {
C.fonsSetSize(s, size) C.fonsSetSize(s, size)
} }
// set_color sets the font color to `color` on the active state.
//
// See also: push_state
// See also: pop_state
// See also: clear_state
[inline] [inline]
pub fn (s &Context) set_color(color u32) { pub fn (s &Context) set_color(color u32) {
C.fonsSetColor(s, color) C.fonsSetColor(s, color)
} }
// set_spacing sets the font spacing to `spacing` on the active state.
//
// See also: push_state
// See also: pop_state
// See also: clear_state
[inline] [inline]
pub fn (s &Context) set_spacing(spacing f32) { pub fn (s &Context) set_spacing(spacing f32) {
C.fonsSetSpacing(s, spacing) C.fonsSetSpacing(s, spacing)
} }
// set_blur sets the font blur effect to `blur` on the active state.
//
// See also: push_state
// See also: pop_state
// See also: clear_state
[inline] [inline]
pub fn (s &Context) set_blur(blur f32) { pub fn (s &Context) set_blur(blur f32) {
C.fonsSetBlur(s, blur) C.fonsSetBlur(s, blur)
} }
// set_align sets the font aligning to `align` on the active state.
//
// See also: push_state
// See also: pop_state
// See also: clear_state
[inline] [inline]
pub fn (s &Context) set_align(align int) { pub fn (s &Context) set_align(align int) {
C.fonsSetAlign(s, align) C.fonsSetAlign(s, align)
} }
// set_font sets the font used for this render on the active state.
// `font_id` is the id of the loaded font.
//
// See also: push_state
// See also: pop_state
// See also: clear_state
[inline] [inline]
pub fn (s &Context) set_font(font int) { pub fn (s &Context) set_font(font_id int) {
C.fonsSetFont(s, font) C.fonsSetFont(s, font_id)
} }
// Draw text // draw_text draws the `text` string at position `x`,`y`.
// The function returns the `x` coordinate of the resulting render.
[inline] [inline]
pub fn (s &Context) draw_text(x f32, y f32, text string) f32 { pub fn (s &Context) draw_text(x f32, y f32, text string) f32 {
return C.fonsDrawText(s, x, y, &char(text.str), &char(0)) return C.fonsDrawText(s, x, y, &char(text.str), &char(0))
} }
// Measure text // text_bounds fills the `bounds` argument with the pixel dimensions
// of the rendered `text` at position `x`,`y`.
//
// `bounds` is expected to be of type `mut bounds := [4]f32{}`.
// Call example: `ctx.text_bounds(0, 0, 'example', &bounds[0])`.
// `bounds[0]` is the `x` coordinate of the top-left point.
// `bounds[1]` is the `y` coordinate of the top-left point.
// `bounds[2]` is the `x` coordinate of the bottom-right point.
// `bounds[3]` is the `y` coordinate of the bottom-right point.
[inline] [inline]
pub fn (s &Context) text_bounds(x f32, y f32, text string, bounds &f32) f32 { pub fn (s &Context) text_bounds(x f32, y f32, text string, bounds &f32) f32 {
return C.fonsTextBounds(s, x, y, &char(text.str), &char(0), bounds) return C.fonsTextBounds(s, x, y, &char(text.str), &char(0), bounds)
} }
// line_bounds fills `miny` and `maxy` with the values of the `minimum`
// and `maximum` line bounds respectively.
[inline] [inline]
pub fn (s &Context) line_bounds(y f32, miny &f32, maxy &f32) { pub fn (s &Context) line_bounds(y f32, miny &f32, maxy &f32) {
C.fonsLineBounds(s, y, miny, maxy) C.fonsLineBounds(s, y, miny, maxy)
} }
// vert_metrics assigns the respective values of `ascender`, `descender` and `lineh`.
[inline] [inline]
pub fn (s &Context) vert_metrics(ascender &f32, descender &f32, lineh &f32) { pub fn (s &Context) vert_metrics(ascender &f32, descender &f32, lineh &f32) {
C.fonsVertMetrics(s, ascender, descender, lineh) C.fonsVertMetrics(s, ascender, descender, lineh)
} }
// Text iterator // text_iter_init initalizes the text iterator `iter`.
[inline] [inline]
pub fn (s &Context) text_iter_init(iter &C.FONStextIter, x f32, y f32, str &char, end &char) int { pub fn (s &Context) text_iter_init(iter &C.FONStextIter, x f32, y f32, str &char, end &char) int {
return C.fonsTextIterInit(s, iter, x, y, str, end) return C.fonsTextIterInit(s, iter, x, y, str, end)
} }
// text_iter_next advances `iter` to the next `quad`.
[inline] [inline]
pub fn (s &Context) text_iter_next(iter &C.FONStextIter, quad &C.FONSquad) int { pub fn (s &Context) text_iter_next(iter &C.FONStextIter, quad &C.FONSquad) int {
return C.fonsTextIterNext(s, iter, quad) return C.fonsTextIterNext(s, iter, quad)
} }
// Pull texture changes // get_texture_data returns the current Context's raw texture data.
// `width` and `height` is assigned the size of the texture dimensions.
[inline] [inline]
pub fn (s &Context) get_texture_data(width &int, height &int) &byte { pub fn (s &Context) get_texture_data(width &int, height &int) &byte {
return &byte(C.fonsGetTextureData(s, width, height)) return &byte(C.fonsGetTextureData(s, width, height))
} }
// validate_texture fills the `dirty` argument with the pixel dimensions
// of the dirty rectangle of the Context's raw texture, if any.
//
// `dirty` is expected to be of type `mut dirty := [4]int{}`.
// Call example: `is_dirty := ctx.validate_texture(&dirty[0])`.
// The function returns `1` if the texture has a dirty rectangle, `0` otherwise.
[inline] [inline]
pub fn (s &Context) validate_texture(dirty &int) int { pub fn (s &Context) validate_texture(dirty &int) int {
return C.fonsValidateTexture(s, dirty) return C.fonsValidateTexture(s, dirty)
} }
// Draws the stash texture for debugging // draw_debug draws the stash texture for debugging.
[inline] [inline]
pub fn (s &Context) draw_debug(x f32, y f32) { pub fn (s &Context) draw_debug(x f32, y f32) {
C.fonsDrawDebug(s, x, y) C.fonsDrawDebug(s, x, y)

View File

@ -1,9 +1,7 @@
import json import json
import os import os
struct DbConfig { struct DbConfig {}
foo int
}
fn test_json_decode_with_optional_arg() { fn test_json_decode_with_optional_arg() {
if ret := print_info() { if ret := print_info() {

View File

@ -332,7 +332,10 @@ pub fn execute(cmd string) Result {
// if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') { // if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
// return Result{ exit_code: -1, output: ';, &&, || and \\n are not allowed in shell commands' } // return Result{ exit_code: -1, output: ';, &&, || and \\n are not allowed in shell commands' }
// } // }
pcmd := if cmd.contains('2>') { cmd } else { '$cmd 2>&1' } pcmd := if cmd.contains('2>') { cmd.clone() } else { '$cmd 2>&1' }
defer {
unsafe { pcmd.free() }
}
f := vpopen(pcmd) f := vpopen(pcmd)
if isnil(f) { if isnil(f) {
return Result{ return Result{

View File

@ -144,24 +144,25 @@ pub fn (mut rng MT19937RNG) u32() u32 {
return u32(ans) return u32(ans)
} }
const mag01 = [u64(0), u64(matrix_a)]
// u64 returns a pseudorandom 64bit int in range `[0, 2)`. // u64 returns a pseudorandom 64bit int in range `[0, 2)`.
[inline] [direct_array_access; inline]
pub fn (mut rng MT19937RNG) u64() u64 { pub fn (mut rng MT19937RNG) u64() u64 {
mag01 := [u64(0), u64(mt19937.matrix_a)]
mut x := u64(0) mut x := u64(0)
mut i := int(0) mut i := int(0)
if rng.mti >= mt19937.nn { if rng.mti >= mt19937.nn {
for i = 0; i < mt19937.nn - mt19937.mm; i++ { for i = 0; i < mt19937.nn - mt19937.mm; i++ {
x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm) x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm)
rng.state[i] = rng.state[i + mt19937.mm] ^ (x >> 1) ^ mag01[int(x & 1)] rng.state[i] = rng.state[i + mt19937.mm] ^ (x >> 1) ^ mt19937.mag01[int(x & 1)]
} }
for i < mt19937.nn - 1 { for i < mt19937.nn - 1 {
x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm) x = (rng.state[i] & mt19937.um) | (rng.state[i + 1] & mt19937.lm)
rng.state[i] = rng.state[i + (mt19937.mm - mt19937.nn)] ^ (x >> 1) ^ mag01[int(x & 1)] rng.state[i] = rng.state[i + (mt19937.mm - mt19937.nn)] ^ (x >> 1) ^ mt19937.mag01[int(x & 1)]
i++ i++
} }
x = (rng.state[mt19937.nn - 1] & mt19937.um) | (rng.state[0] & mt19937.lm) x = (rng.state[mt19937.nn - 1] & mt19937.um) | (rng.state[0] & mt19937.lm)
rng.state[mt19937.nn - 1] = rng.state[mt19937.mm - 1] ^ (x >> 1) ^ mag01[int(x & 1)] rng.state[mt19937.nn - 1] = rng.state[mt19937.mm - 1] ^ (x >> 1) ^ mt19937.mag01[int(x & 1)]
rng.mti = 0 rng.mti = 0
} }
x = rng.state[rng.mti] x = rng.state[rng.mti]

View File

@ -29,7 +29,7 @@ pub fn (mut rng MuslRNG) seed(seed_data []u32) {
// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`. // byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
[inline] [inline]
fn (mut rng MuslRNG) byte() byte { pub fn (mut rng MuslRNG) byte() byte {
if rng.bytes_left >= 1 { if rng.bytes_left >= 1 {
rng.bytes_left -= 1 rng.bytes_left -= 1
value := byte(rng.buffer) value := byte(rng.buffer)
@ -70,7 +70,7 @@ fn temper(prev u32) u32 {
} }
// u32 returns a pseudorandom 32-bit unsigned integer (`u32`). // u32 returns a pseudorandom 32-bit unsigned integer (`u32`).
fn (mut rng MuslRNG) u32() u32 { pub fn (mut rng MuslRNG) u32() u32 {
rng.state = rng.state * 1103515245 + 12345 rng.state = rng.state * 1103515245 + 12345
// We are not dividing by 2 (or shifting right by 1) // We are not dividing by 2 (or shifting right by 1)
// because we want all 32-bits of random data // because we want all 32-bits of random data

View File

@ -39,7 +39,7 @@ pub fn (mut rng PCG32RNG) seed(seed_data []u32) {
// byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`. // byte returns a uniformly distributed pseudorandom 8-bit unsigned positive `byte`.
[inline] [inline]
fn (mut rng PCG32RNG) byte() byte { pub fn (mut rng PCG32RNG) byte() byte {
if rng.bytes_left >= 1 { if rng.bytes_left >= 1 {
rng.bytes_left -= 1 rng.bytes_left -= 1
value := byte(rng.buffer) value := byte(rng.buffer)
@ -70,7 +70,7 @@ pub fn (mut rng PCG32RNG) u16() u16 {
// u32 returns a pseudorandom unsigned `u32`. // u32 returns a pseudorandom unsigned `u32`.
[inline] [inline]
fn (mut rng PCG32RNG) u32() u32 { pub fn (mut rng PCG32RNG) u32() u32 {
oldstate := rng.state oldstate := rng.state
rng.state = oldstate * (6364136223846793005) + rng.inc rng.state = oldstate * (6364136223846793005) + rng.inc
xorshifted := u32(((oldstate >> u64(18)) ^ oldstate) >> u64(27)) xorshifted := u32(((oldstate >> u64(18)) ^ oldstate) >> u64(27))

View File

@ -1,26 +1,47 @@
module strconv module strconv
/* // Copyright (c) 2019-2022 Dario Deledda. All rights reserved.
atof util // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
//
// This file contains utilities for converting a string to a f64 variable.
// IEEE 754 standard is used.
// Know limitation: limited to 18 significant digits
//
// The code is inspired by:
// Grzegorz Kraszewski krashan@teleinfo.pb.edu.pl
// URL: http://krashan.ppa.pl/articles/stringtofloat/
// Original license: MIT
// 96 bit operation utilities
//
// Note: when u128 will be available, these function can be refactored.
Copyright (c) 2019-2022 Dario Deledda. All rights reserved. // f32 constants
Use of this source code is governed by an MIT license pub const (
that can be found in the LICENSE file. single_plus_zero = u32(0x0000_0000)
single_minus_zero = u32(0x8000_0000)
single_plus_infinity = u32(0x7F80_0000)
single_minus_infinity = u32(0xFF80_0000)
)
This file contains utilities for convert a string in a f64 variable // f64 constants
IEEE 754 standard is used pub const (
digits = 18
double_plus_zero = u64(0x0000000000000000)
double_minus_zero = u64(0x8000000000000000)
double_plus_infinity = u64(0x7FF0000000000000)
double_minus_infinity = u64(0xFFF0000000000000)
)
Know limitation: // char constants
- limited to 18 significant digits pub const (
c_dpoint = `.`
The code is inspired by: c_plus = `+`
Grzegorz Kraszewski krashan@teleinfo.pb.edu.pl c_minus = `-`
URL: http://krashan.ppa.pl/articles/stringtofloat/ c_zero = `0`
Original license: MIT c_nine = `9`
c_ten = u32(10)
96 bit operation utilities )
Note: when u128 will be available these function can be refactored
*/
// right logical shift 96 bit // right logical shift 96 bit
fn lsr96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) { fn lsr96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) {
@ -78,48 +99,7 @@ fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) {
return r2, r1, r0 return r2, r1, r0
} }
// Constants
pub const (
//
// f32 constants
//
single_plus_zero = u32(0x0000_0000)
single_minus_zero = u32(0x8000_0000)
single_plus_infinity = u32(0x7F80_0000)
single_minus_infinity = u32(0xFF80_0000)
//
// f64 constants
//
digits = 18
double_plus_zero = u64(0x0000000000000000)
double_minus_zero = u64(0x8000000000000000)
double_plus_infinity = u64(0x7FF0000000000000)
double_minus_infinity = u64(0xFFF0000000000000)
//
// Possible parser return values.
//
parser_ok = 0 // parser finished OK
parser_pzero = 1 // no digits or number is smaller than +-2^-1022
parser_mzero = 2 // number is negative, module smaller
parser_pinf = 3 // number is higher than +HUGE_VAL
parser_minf = 4 // number is lower than -HUGE_VAL
parser_invalid_number = 5 // invalid number, used for '#@%^' for example
//
// char constants
// Note: Modify these if working with non-ASCII encoding
//
c_dpoint = `.`
c_plus = `+`
c_minus = `-`
c_zero = `0`
c_nine = `9`
c_ten = u32(10)
)
// Utility functions // Utility functions
// NOTE: Modify these if working with non-ASCII encoding
fn is_digit(x byte) bool { fn is_digit(x byte) bool {
return (x >= strconv.c_zero && x <= strconv.c_nine) == true return (x >= strconv.c_zero && x <= strconv.c_nine) == true
} }
@ -132,14 +112,21 @@ fn is_exp(x byte) bool {
return (x == `E` || x == `e`) == true return (x == `E` || x == `e`) == true
} }
/* // Possible parser return values.
String parser enum ParserState {
NOTE: #TOFIX need one char after the last char of the number ok // parser finished OK
*/ pzero // no digits or number is smaller than +-2^-1022
mzero // number is negative, module smaller
pinf // number is higher than +HUGE_VAL
minf // number is lower than -HUGE_VAL
invalid_number // invalid number, used for '#@%^' for example
}
fn parser(s string) (int, PrepNumber) { // parser tries to parse the given string into a number
// NOTE: #TOFIX need one char after the last char of the number
fn parser(s string) (ParserState, PrepNumber) {
mut digx := 0 mut digx := 0
mut result := strconv.parser_ok mut result := ParserState.ok
mut expneg := false mut expneg := false
mut expexp := 0 mut expexp := 0
mut i := 0 mut i := 0
@ -216,45 +203,45 @@ fn parser(s string) (int, PrepNumber) {
pn.exponent += expexp pn.exponent += expexp
if pn.mantissa == 0 { if pn.mantissa == 0 {
if pn.negative { if pn.negative {
result = strconv.parser_mzero result = .mzero
} else { } else {
result = strconv.parser_pzero result = .pzero
} }
} else if pn.exponent > 309 { } else if pn.exponent > 309 {
if pn.negative { if pn.negative {
result = strconv.parser_minf result = .minf
} else { } else {
result = strconv.parser_pinf result = .pinf
} }
} else if pn.exponent < -328 { } else if pn.exponent < -328 {
if pn.negative { if pn.negative {
result = strconv.parser_mzero result = .mzero
} else { } else {
result = strconv.parser_pzero result = .pzero
} }
} }
if i == 0 && s.len > 0 { if i == 0 && s.len > 0 {
return strconv.parser_invalid_number, pn return ParserState.invalid_number, pn
} }
return result, pn return result, pn
} }
/* // converter returns a u64 with the bit image of the f64 number
Converter to the bit form of the f64 number
*/
// converter return a u64 with the bit image of the f64 number
fn converter(mut pn PrepNumber) u64 { fn converter(mut pn PrepNumber) u64 {
mut binexp := 92 mut binexp := 92
mut s2 := u32(0) // 96-bit precision integer // s0,s1,s2 are the parts of a 96-bit precision integer
mut s2 := u32(0)
mut s1 := u32(0) mut s1 := u32(0)
mut s0 := u32(0) mut s0 := u32(0)
mut q2 := u32(0) // 96-bit precision integer // q0,q1,q2 are the parts of a 96-bit precision integer
mut q2 := u32(0)
mut q1 := u32(0) mut q1 := u32(0)
mut q0 := u32(0) mut q0 := u32(0)
mut r2 := u32(0) // 96-bit precision integer // r0,r1,r2 are the parts of a 96-bit precision integer
mut r2 := u32(0)
mut r1 := u32(0) mut r1 := u32(0)
mut r0 := u32(0) mut r0 := u32(0)
//
mask28 := u32(u64(0xF) << 28) mask28 := u32(u64(0xF) << 28)
mut result := u64(0) mut result := u64(0)
// working on 3 u32 to have 96 bit precision // working on 3 u32 to have 96 bit precision
@ -404,35 +391,30 @@ fn converter(mut pn PrepNumber) u64 {
return result return result
} }
// Public functions // atof64 parses the string `s`, and if possible, converts it into a f64 number
// atof64 return a f64 from a string doing a parsing operation
pub fn atof64(s string) ?f64 { pub fn atof64(s string) ?f64 {
if s.len == 0 { if s.len == 0 {
return error('expected a number found an empty string') return error('expected a number found an empty string')
} }
mut pn := PrepNumber{}
mut res_parsing := 0
mut res := Float64u{} mut res := Float64u{}
mut res_parsing, mut pn := parser(s)
res_parsing, pn = parser(s)
match res_parsing { match res_parsing {
strconv.parser_ok { .ok {
res.u = converter(mut pn) res.u = converter(mut pn)
} }
strconv.parser_pzero { .pzero {
res.u = strconv.double_plus_zero res.u = strconv.double_plus_zero
} }
strconv.parser_mzero { .mzero {
res.u = strconv.double_minus_zero res.u = strconv.double_minus_zero
} }
strconv.parser_pinf { .pinf {
res.u = strconv.double_plus_infinity res.u = strconv.double_plus_infinity
} }
strconv.parser_minf { .minf {
res.u = strconv.double_minus_infinity res.u = strconv.double_minus_infinity
} }
else { .invalid_number {
return error('not a number') return error('not a number')
} }
} }

View File

@ -142,11 +142,11 @@ pub fn h_divider(divider string) string {
// ==== TITLE ========================= // ==== TITLE =========================
pub fn header_left(text string, divider string) string { pub fn header_left(text string, divider string) string {
plain_text := strip_ansi(text) plain_text := strip_ansi(text)
xcols, _ := get_terminal_size() xcols, _ := get_terminal_size() // can get 0 in lldb/gdb
cols := imax(1, xcols) cols := imax(1, xcols)
relement := if divider.len > 0 { divider } else { ' ' } relement := if divider.len > 0 { divider } else { ' ' }
hstart := relement.repeat(4)[0..4] hstart := relement.repeat(4)[0..4]
remaining_cols := (cols - (hstart.len + 1 + plain_text.len + 1)) remaining_cols := imax(0, (cols - (hstart.len + 1 + plain_text.len + 1)))
hend := relement.repeat((remaining_cols + 1) / relement.len)[0..remaining_cols] hend := relement.repeat((remaining_cols + 1) / relement.len)[0..remaining_cols]
return '$hstart $text $hend' return '$hstart $text $hend'
} }

View File

@ -3,14 +3,13 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module scanner module scanner
import math
import toml.input import toml.input
import toml.token import toml.token
import toml.util import toml.util
pub const ( pub const (
digit_extras = [`_`, `.`, `x`, `o`, `b`, `e`, `E`] digit_extras = [`_`, `.`, `x`, `o`, `b`, `e`, `E`]
end_of_text = math.max_u32 end_of_text = 4294967295
) )
// Scanner contains the necessary fields for the state of the scan process. // Scanner contains the necessary fields for the state of the scan process.
@ -346,7 +345,7 @@ fn (mut s Scanner) new_token(kind token.Kind, lit string, len int) token.Token {
return token.Token{ return token.Token{
kind: kind kind: kind
lit: lit lit: lit
col: math.max(1, col) col: if col < 1 { 1 } else { col }
line_nr: s.line_nr + 1 line_nr: s.line_nr + 1
pos: s.pos - s.header_len - len + 1 pos: s.pos - s.header_len - len + 1
len: len len: len

View File

@ -1175,6 +1175,13 @@ fn (t Table) shorten_user_defined_typenames(originalname string, import_aliases
} else if res in import_aliases { } else if res in import_aliases {
res = import_aliases[res] res = import_aliases[res]
} else { } else {
// FIXME: clean this case and remove the following if
// because it is an hack to format well the type when
// there is a []modul.name
if res.contains('[]') {
idx := res.index('.') or { -1 }
return res[idx + 1..]
}
// types defined by the user // types defined by the user
// mod.submod.submod2.Type => submod2.Type // mod.submod.submod2.Type => submod2.Type
mut parts := res.split('.') mut parts := res.split('.')

View File

@ -124,6 +124,7 @@ mut:
inside_println_arg bool inside_println_arg bool
inside_decl_rhs bool inside_decl_rhs bool
inside_if_guard bool // true inside the guard condition of `if x := opt() {}` inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
comptime_call_pos int // needed for correctly checking use before decl for templates
} }
pub fn new_checker(table &ast.Table, pref &pref.Preferences) &Checker { pub fn new_checker(table &ast.Table, pref &pref.Preferences) &Checker {
@ -3127,9 +3128,16 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
return obj.typ return obj.typ
} }
ast.Var { ast.Var {
// incase var was not marked as used yet (vweb tmpl) // inside vweb tmpl ident positions are meaningless, use the position of the comptime call.
// obj.is_used = true // if the variable is declared before the comptime call then we can assume all is well.
if node.pos.pos < obj.pos.pos { // `node.name !in node.scope.objects && node.scope.start_pos < c.comptime_call_pos` (inherited)
node_pos := if c.pref.is_vweb && node.name !in node.scope.objects
&& node.scope.start_pos < c.comptime_call_pos {
c.comptime_call_pos
} else {
node.pos.pos
}
if node_pos < obj.pos.pos {
c.error('undefined variable `$node.name` (used before declaration)', c.error('undefined variable `$node.name` (used before declaration)',
node.pos) node.pos)
} }

View File

@ -36,28 +36,8 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
is_vweb: true is_vweb: true
} }
mut c2 := new_checker(c.table, pref2) mut c2 := new_checker(c.table, pref2)
c2.comptime_call_pos = node.pos.pos
c2.check(node.vweb_tmpl) c2.check(node.vweb_tmpl)
mut caller_scope := c.fn_scope.innermost(node.pos.pos)
mut i := 0 // tmp counter var for skipping first three tmpl vars
for k, _ in c2.file.scope.children[0].objects {
if i < 2 {
// Skip first three because they are tmpl vars see vlib/vweb/tmpl/tmpl.v
i++
continue
}
tmpl_obj := unsafe { c2.file.scope.children[0].objects[k] }
if tmpl_obj is ast.Var {
if mut caller_var := caller_scope.find_var(tmpl_obj.name) {
// var is used in the tmpl so mark it as used in the caller
caller_var.is_used = true
// update props from the caller scope var to the tmpl scope var
c2.file.scope.children[0].objects[k] = ast.Var{
...(*caller_var)
pos: tmpl_obj.pos
}
}
}
}
c.warnings << c2.warnings c.warnings << c2.warnings
c.errors << c2.errors c.errors << c2.errors
c.notices << c2.notices c.notices << c2.notices

View File

@ -9,6 +9,22 @@ pub fn (mut c Checker) array_init(mut node ast.ArrayInit) ast.Type {
mut elem_type := ast.void_type mut elem_type := ast.void_type
// []string - was set in parser // []string - was set in parser
if node.typ != ast.void_type { if node.typ != ast.void_type {
if node.elem_type != 0 {
elem_sym := c.table.sym(node.elem_type)
if elem_sym.kind == .struct_ {
elem_info := elem_sym.info as ast.Struct
if elem_info.generic_types.len > 0 && elem_info.concrete_types.len == 0
&& !node.elem_type.has_flag(.generic) {
if c.table.cur_concrete_types.len == 0 {
c.error('generic struct must specify type parameter, e.g. Foo<int>',
node.elem_type_pos)
} else {
c.error('generic struct must specify type parameter, e.g. Foo<T>',
node.elem_type_pos)
}
}
}
}
if node.exprs.len == 0 { if node.exprs.len == 0 {
if node.has_cap { if node.has_cap {
c.check_array_init_para_type('cap', node.cap_expr, node.pos) c.check_array_init_para_type('cap', node.cap_expr, node.pos)
@ -244,6 +260,22 @@ pub fn (mut c Checker) map_init(mut node ast.MapInit) ast.Type {
// `x := map[string]string` - set in parser // `x := map[string]string` - set in parser
if node.typ != 0 { if node.typ != 0 {
info := c.table.sym(node.typ).map_info() info := c.table.sym(node.typ).map_info()
if info.value_type != 0 {
val_sym := c.table.sym(info.value_type)
if val_sym.kind == .struct_ {
val_info := val_sym.info as ast.Struct
if val_info.generic_types.len > 0 && val_info.concrete_types.len == 0
&& !info.value_type.has_flag(.generic) {
if c.table.cur_concrete_types.len == 0 {
c.error('generic struct `$val_sym.name` must specify type parameter, e.g. Foo<int>',
node.pos)
} else {
c.error('generic struct `$val_sym.name` must specify type parameter, e.g. Foo<T>',
node.pos)
}
}
}
}
c.ensure_type_exists(info.key_type, node.pos) or {} c.ensure_type_exists(info.key_type, node.pos) or {}
c.ensure_type_exists(info.value_type, node.pos) or {} c.ensure_type_exists(info.value_type, node.pos) or {}
node.key_type = info.key_type node.key_type = info.key_type

View File

@ -1726,6 +1726,10 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ ast.Type, node ast
if is_map && arg_expr.return_type in [ast.void_type, 0] { if is_map && arg_expr.return_type in [ast.void_type, 0] {
c.error('type mismatch, `$arg_expr.name` does not return anything', arg_expr.pos) c.error('type mismatch, `$arg_expr.name` does not return anything', arg_expr.pos)
} else if !is_map && arg_expr.return_type != ast.bool_type { } else if !is_map && arg_expr.return_type != ast.bool_type {
if arg_expr.or_block.kind != .absent && arg_expr.return_type.has_flag(.optional)
&& arg_expr.return_type.clear_flag(.optional) == ast.bool_type {
return
}
c.error('type mismatch, `$arg_expr.name` must return a bool', arg_expr.pos) c.error('type mismatch, `$arg_expr.name` must return a bool', arg_expr.pos)
} }
} }

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/array_of_generic_struct_init_err.vv:6:15: error: generic struct must specify type parameter, e.g. Foo<int>
4 |
5 | fn main() {
6 | mut arr := []Item{}
| ~~~~
7 | }

View File

@ -0,0 +1,7 @@
struct Item<T>{
val T
}
fn main() {
mut arr := []Item{}
}

View File

@ -0,0 +1,27 @@
vlib/v/checker/tests/check_err_msg_with_generics.vv:15:10: error: cannot cast struct `BSTree<Result<[]Token, Err<string>>>` to `int`
13 | fn test_err_msg() {
14 | typ := datatypes.BSTree<Result<[]Token, Err<string>>>{}
15 | println(int(typ))
| ~~~~~~~~
16 | }
vlib/datatypes/bstree.v:190:17: error: cannot append `T` to `[]T`
188 | }
189 | bst.in_order_traversal_helper(node.left, mut result)
190 | result << node.value
| ~~~~~
191 | bst.in_order_traversal_helper(node.right, mut result)
192 | }
vlib/datatypes/bstree.v:210:17: error: cannot append `T` to `[]T`
208 | bst.post_order_traversal_helper(node.left, mut result)
209 | bst.post_order_traversal_helper(node.right, mut result)
210 | result << node.value
| ~~~~~
211 | }
212 |
vlib/datatypes/bstree.v:226:17: error: cannot append `T` to `[]T`
224 | return
225 | }
226 | result << node.value
| ~~~~~
227 | bst.pre_order_traversal_helper(node.left, mut result)
228 | bst.pre_order_traversal_helper(node.right, mut result)

View File

@ -0,0 +1,16 @@
import datatypes
type Result<T, U> = Err<U> | Ok<T>
struct Ok<T> {
value T
}
struct Err<U> {
value U
}
fn test_err_msg() {
typ := datatypes.BSTree<Result<[]Token, Err<string>>>{}
println(int(typ))
}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/map_of_generic_struct_init_err.vv:6:11: error: generic struct `Item` must specify type parameter, e.g. Foo<int>
4 |
5 | fn main() {
6 | mut m := map[string]Item{}
| ~~~~~~~~~~~~~~~~~
7 | }

View File

@ -0,0 +1,7 @@
struct Item<T>{
val T
}
fn main() {
mut m := map[string]Item{}
}

View File

@ -0,0 +1,13 @@
vlib/v/checker/tests/struct_field_name_err.vv:2:2: error: field name `Architecture` cannot contain uppercase letters, use snake_case instead
1 | struct Release {
2 | Architecture []string
| ~~~~~~~~~~~~~~~~~~~~~
3 | Components []string
4 | }
vlib/v/checker/tests/struct_field_name_err.vv:3:2: error: field name `Components` cannot contain uppercase letters, use snake_case instead
1 | struct Release {
2 | Architecture []string
3 | Components []string
| ~~~~~~~~~~~~~~~~~~~~~
4 | }
5 |

View File

@ -0,0 +1,9 @@
struct Release {
Architecture []string
Components []string
}
fn main() {
r := Release{}
println(r)
}

View File

@ -673,7 +673,11 @@ fn (mut g Gen) gen_array_contains_methods() {
fn_name := '${left_type_str}_contains' fn_name := '${left_type_str}_contains'
left_info := left_final_sym.info as ast.Array left_info := left_final_sym.info as ast.Array
mut elem_type_str := g.typ(left_info.elem_type) mut elem_type_str := g.typ(left_info.elem_type)
elem_sym := g.table.sym(left_info.elem_type) mut elem_sym := g.table.sym(left_info.elem_type)
if elem_sym.kind == .alias {
info := elem_sym.info as ast.Alias
elem_sym = g.table.sym(info.parent_type)
}
if elem_sym.kind == .function { if elem_sym.kind == .function {
left_type_str = 'Array_voidptr' left_type_str = 'Array_voidptr'
elem_type_str = 'voidptr' elem_type_str = 'voidptr'
@ -751,7 +755,11 @@ fn (mut g Gen) gen_array_index_methods() {
fn_name := '${left_type_str}_index' fn_name := '${left_type_str}_index'
info := final_left_sym.info as ast.Array info := final_left_sym.info as ast.Array
mut elem_type_str := g.typ(info.elem_type) mut elem_type_str := g.typ(info.elem_type)
elem_sym := g.table.sym(info.elem_type) mut elem_sym := g.table.sym(info.elem_type)
if elem_sym.kind == .alias {
info_t := elem_sym.info as ast.Alias
elem_sym = g.table.sym(info_t.parent_type)
}
if elem_sym.kind == .function { if elem_sym.kind == .function {
left_type_str = 'Array_voidptr' left_type_str = 'Array_voidptr'
elem_type_str = 'voidptr' elem_type_str = 'voidptr'

View File

@ -238,11 +238,12 @@ fn (mut g Gen) gen_assign_stmt(node_ ast.AssignStmt) {
} else { } else {
g.out.go_back_to(pos) g.out.go_back_to(pos)
is_var_mut := !is_decl && left.is_auto_deref_var() is_var_mut := !is_decl && left.is_auto_deref_var()
addr := if is_var_mut { '' } else { '&' } addr_left := if is_var_mut { '' } else { '&' }
g.writeln('') g.writeln('')
g.write('memcpy($addr') g.write('memcpy($addr_left')
g.expr(left) g.expr(left)
g.writeln(', &$v_var, sizeof($arr_typ));') addr_val := if is_fixed_array_var { '' } else { '&' }
g.writeln(', $addr_val$v_var, sizeof($arr_typ));')
} }
g.is_assign_lhs = false g.is_assign_lhs = false
} else { } else {

View File

@ -972,7 +972,7 @@ fn (g Gen) optional_type_text(styp string, base string) string {
ret := 'struct $styp { ret := 'struct $styp {
byte state; byte state;
IError err; IError err;
byte data[sizeof($size)]; byte data[sizeof($size) > 0 ? sizeof($size) : 1];
}' }'
return ret return ret
} }
@ -2645,12 +2645,13 @@ fn (mut g Gen) autofree_variable(v ast.Var) {
g.autofree_var_call('string_free', v) g.autofree_var_call('string_free', v)
return return
} }
if sym.has_method('free') { if g.pref.experimental && v.typ.is_ptr() && sym.name.after('.')[0].is_capital() {
g.autofree_var_call(free_fn, v)
} else if g.pref.experimental && v.typ.is_ptr() && sym.name.after('.')[0].is_capital() {
// Free user reference types // Free user reference types
g.autofree_var_call('free', v) g.autofree_var_call('free', v)
} }
if sym.has_method('free') {
g.autofree_var_call(free_fn, v)
}
} }
fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) { fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) {
@ -2698,8 +2699,12 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) {
if v.typ == ast.error_type && !v.is_autofree_tmp { if v.typ == ast.error_type && !v.is_autofree_tmp {
return return
} }
if v.is_auto_heap {
af.writeln('\t${free_fn_name}(${c_name(v.name)}); // autofreed heap var $g.cur_mod.name $g.is_builtin_mod')
} else {
af.writeln('\t${free_fn_name}(&${c_name(v.name)}); // autofreed var $g.cur_mod.name $g.is_builtin_mod') af.writeln('\t${free_fn_name}(&${c_name(v.name)}); // autofreed var $g.cur_mod.name $g.is_builtin_mod')
} }
}
g.autofree_scope_stmts << af.str() g.autofree_scope_stmts << af.str()
} }
@ -3697,10 +3702,8 @@ fn (mut g Gen) ident(node ast.Ident) {
g.write('${name}.val') g.write('${name}.val')
return return
} }
// TODO: investigate why node.obj is pointing to outdated ScopeObject? v := node.obj
// v := node.obj if v is ast.Var {
// if v is ast.Var {
if v := node.scope.find_var(node.name) {
is_auto_heap = v.is_auto_heap && (!g.is_assign_lhs || g.assign_op != .decl_assign) is_auto_heap = v.is_auto_heap && (!g.is_assign_lhs || g.assign_op != .decl_assign)
if is_auto_heap { if is_auto_heap {
g.write('(*(') g.write('(*(')

View File

@ -1206,6 +1206,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
// `json__encode` => `json__encode_User` // `json__encode` => `json__encode_User`
// encode_name := c_name(name) + '_' + util.no_dots(json_type_str) // encode_name := c_name(name) + '_' + util.no_dots(json_type_str)
encode_name := js_enc_name(json_type_str) encode_name := js_enc_name(json_type_str)
g.empty_line = true
g.writeln('// json.encode') g.writeln('// json.encode')
g.write('cJSON* $json_obj = ${encode_name}(') g.write('cJSON* $json_obj = ${encode_name}(')
if node.args[0].typ.is_ptr() { if node.args[0].typ.is_ptr() {
@ -1225,6 +1226,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
typ := c_name(g.typ(ast_type.typ)) typ := c_name(g.typ(ast_type.typ))
fn_name := c_name(name) + '_' + typ fn_name := c_name(name) + '_' + typ
g.gen_json_for_type(ast_type.typ) g.gen_json_for_type(ast_type.typ)
g.empty_line = true
g.writeln('// json.decode') g.writeln('// json.decode')
g.write('cJSON* $json_obj = json__json_parse(') g.write('cJSON* $json_obj = json__json_parse(')
// Skip the first argument in json.decode which is a type // Skip the first argument in json.decode which is a type
@ -1233,7 +1235,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.call_args(node) g.call_args(node)
g.writeln(');') g.writeln(');')
tmp2 = g.new_tmp_var() tmp2 = g.new_tmp_var()
g.writeln('Option_$typ $tmp2 = $fn_name ($json_obj);') g.writeln('Option_$typ $tmp2 = ${fn_name}($json_obj);')
} }
if !g.is_autofree { if !g.is_autofree {
g.write('cJSON_Delete($json_obj); // del') g.write('cJSON_Delete($json_obj); // del')

View File

@ -626,7 +626,8 @@ fn (mut g Gen) infix_expr_left_shift_op(node ast.InfixExpr) {
if elem_sym.kind == .function { if elem_sym.kind == .function {
g.write(', _MOV((voidptr[]){ ') g.write(', _MOV((voidptr[]){ ')
} else if elem_is_array_var { } else if elem_is_array_var {
g.write(', &') addr := if elem_sym.kind == .array_fixed { '' } else { '&' }
g.write(', $addr')
} else { } else {
g.write(', _MOV(($elem_type_str[]){ ') g.write(', _MOV(($elem_type_str[]){ ')
} }

View File

@ -245,10 +245,6 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
println('$path:${i + 1}: $line') println('$path:${i + 1}: $line')
} }
} }
mut scope := &ast.Scope{
start_pos: 0
parent: p.table.global_scope
}
$if trace_comptime ? { $if trace_comptime ? {
println('') println('')
println('>>> template for $path:') println('>>> template for $path:')
@ -256,25 +252,11 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
println('>>> end of template END') println('>>> end of template END')
println('') println('')
} }
mut file := parse_comptime(v_code, p.table, p.pref, scope) // the tmpl inherits all parent scopes. previous functionality was just to
// inherit the scope from which the comptime call was made and no parents.
// this is much simpler and allws access to globals. can be changed if needed.
mut file := parse_comptime(tmpl_path, v_code, p.table, p.pref, p.scope)
file.path = tmpl_path file.path = tmpl_path
// copy vars from current fn scope into vweb_tmpl scope
for mut stmt in file.stmts {
if mut stmt is ast.FnDecl {
if stmt.name == 'main.vweb_tmpl_$tmp_fn_name' {
for _, mut obj in p.scope.objects {
if mut obj is ast.Var {
stmt.scope.register(ast.Var{
...obj
is_used: true
pos: stmt.body_pos
})
}
}
break
}
}
}
return ast.ComptimeCall{ return ast.ComptimeCall{
scope: 0 scope: 0
is_vweb: true is_vweb: true

View File

@ -115,11 +115,12 @@ pub fn parse_stmt(text string, table &ast.Table, scope &ast.Scope) ast.Stmt {
return p.stmt(false) return p.stmt(false)
} }
pub fn parse_comptime(text string, table &ast.Table, pref &pref.Preferences, scope &ast.Scope) &ast.File { pub fn parse_comptime(tmpl_path string, text string, table &ast.Table, pref &pref.Preferences, scope &ast.Scope) &ast.File {
$if trace_parse_comptime ? { $if trace_parse_comptime ? {
eprintln('> ${@MOD}.${@FN} text: $text') eprintln('> ${@MOD}.${@FN} text: $text')
} }
mut p := Parser{ mut p := Parser{
file_name: tmpl_path
scanner: scanner.new_scanner(text, .skip_comments, pref) scanner: scanner.new_scanner(text, .skip_comments, pref)
table: table table: table
pref: pref pref: pref
@ -2139,10 +2140,12 @@ pub fn (mut p Parser) name_expr() ast.Expr {
p.expr_mod = '' p.expr_mod = ''
// `map[string]int` initialization // `map[string]int` initialization
if p.tok.lit == 'map' && p.peek_tok.kind == .lsbr { if p.tok.lit == 'map' && p.peek_tok.kind == .lsbr {
mut pos := p.tok.pos()
map_type := p.parse_map_type() map_type := p.parse_map_type()
if p.tok.kind == .lcbr { if p.tok.kind == .lcbr {
p.next() p.next()
if p.tok.kind == .rcbr { if p.tok.kind == .rcbr {
pos = pos.extend(p.tok.pos())
p.next() p.next()
} else { } else {
if p.pref.is_fmt { if p.pref.is_fmt {
@ -2155,7 +2158,7 @@ pub fn (mut p Parser) name_expr() ast.Expr {
} }
return ast.MapInit{ return ast.MapInit{
typ: map_type typ: map_type
pos: p.prev_tok.pos() pos: pos
} }
} }
// `chan typ{...}` // `chan typ{...}`

View File

@ -184,7 +184,8 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
p.next() p.next()
is_field_volatile = true is_field_volatile = true
} }
is_embed := ((p.tok.lit.len > 1 && p.tok.lit[0].is_capital()) is_embed := ((p.tok.lit.len > 1 && p.tok.lit[0].is_capital()
&& (p.peek_tok.kind != .lsbr || p.peek_token(2).kind != .rsbr))
|| p.peek_tok.kind == .dot) && language == .v && p.peek_tok.kind != .key_fn || p.peek_tok.kind == .dot) && language == .v && p.peek_tok.kind != .key_fn
is_on_top := ast_fields.len == 0 && !(is_field_mut || is_field_global) is_on_top := ast_fields.len == 0 && !(is_field_mut || is_field_global)
mut field_name := '' mut field_name := ''

View File

@ -634,7 +634,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
eprintln('Use `v $arg` instead.') eprintln('Use `v $arg` instead.')
exit(1) exit(1)
} }
if arg[0] == `-` { if arg.len != 0 && arg[0] == `-` {
if arg[1..] in pref.list_of_flags_with_param { if arg[1..] in pref.list_of_flags_with_param {
// skip parameter // skip parameter
i++ i++

View File

@ -0,0 +1,8 @@
module pref
fn test_check_parametes() {
// reproducing issue https://github.com/vlang/v/issues/13983
_, cmd := parse_args_and_show_errors(['help'], [''], true)
// no command found from args
assert cmd == ''
}

View File

@ -30,3 +30,12 @@ fn test_array_eval_count() {
a4 = Counter{} a4 = Counter{}
assert a4.new_arr('all() failed').all(it == 2) == false assert a4.new_arr('all() failed').all(it == 2) == false
} }
fn opt_bool_fn() ?bool {
return true
}
fn test_any_called_with_opt_bool_fn() ? {
_ := [1, 2, 3].any(opt_bool_fn() ?)
assert true
}

View File

@ -0,0 +1,2 @@
$a.name
$b

View File

@ -0,0 +1,13 @@
[heap]
struct MyHeapStruct {
name string
}
// make sure dereferencing of heap stucts works in selector expr (in tmpl),
fn test_heap_struct_dereferencing_in_selector_expr() {
a := MyHeapStruct{
name: 'my_heap_struct_a'
}
b := 2
$tmpl('comptime_call_tmpl_variable_scope_test.tpl')
}

View File

@ -0,0 +1,44 @@
struct Test1 {
mut:
value [4]int
}
fn (mut t Test1) set(new_value [4]int) {
t.value = new_value
}
fn test_fn_with_fixed_array_argument_1() {
mut t := Test1{}
println(t)
assert '$t.value' == '[0, 0, 0, 0]'
t.set([1, 2, 3, 4]!)
println(t)
assert '$t.value' == '[1, 2, 3, 4]'
}
struct Test2 {
mut:
fixed_value [2][4]int
dynamic_value [][4]int
}
fn (mut t Test2) set(index int, new_value [4]int) {
t.fixed_value[index] = new_value
t.dynamic_value << new_value
}
fn test_fn_with_fixed_array_argument_2() {
mut t := Test2{}
println(t)
assert '$t.fixed_value' == '[[0, 0, 0, 0], [0, 0, 0, 0]]'
assert '$t.dynamic_value' == '[]'
t.set(0, [1, 2, 3, 4]!)
println(t)
assert '$t.fixed_value' == '[[1, 2, 3, 4], [0, 0, 0, 0]]'
assert '$t.dynamic_value' == '[[1, 2, 3, 4]]'
}

View File

@ -16,8 +16,6 @@ fn create(x int) &Foo {
fn (f &Foo) free() { fn (f &Foo) free() {
println('> freeing Foo $f.x at address: ${voidptr(f)} | frees.len: $frees.len') println('> freeing Foo $f.x at address: ${voidptr(f)} | frees.len: $frees.len')
frees << f.x frees << f.x
// TODO: this should NOT be necessary - the compiler should do it automatically in the parent scope
unsafe { free(f) }
} }
fn create_some_foos() { fn create_some_foos() {