Compare commits

...

57 Commits

Author SHA1 Message Date
Alexander Medvednikov 428fd7f57f all: do not allow uninitialized function pointers 2023-08-03 21:06:36 +03:00
yuyi 453137384e
ast: clean up stringify_fn_decl() and stringify_anon_decl(), make them methods on ast.Table (#19053) 2023-08-03 19:50:37 +03:00
Swastik Baranwal 6a4bfef2c5
parser: disallow having builtin type as type names for `enum`, `sum type` and `alias` (#19043) 2023-08-03 11:42:31 +03:00
shove 9f5e9ba1cf
cgen: fix an error with ptr interpolation (fix #19048) (#19049) 2023-08-03 11:18:22 +03:00
blackshirt ef5c3cdb73
math.unsigned: change uint256_from_dec_str to return a result, instead of an option (#19041) 2023-08-03 10:18:21 +03:00
yuyi 5ec7ee916a
parser: fix formatting comptime if expr script (v fmt no longer eats the body of top level `$if xyz ? {}`) (#19044) 2023-08-03 09:30:00 +03:00
shove b556f1302f
parser: fix parse error in the type of a ref array when the element type is a structure of another mod(fix #19033) (#19039) 2023-08-03 09:25:03 +03:00
kbkpbot fe9bdd4168
sync: make sync.Direction public (#19047) 2023-08-03 09:22:48 +03:00
Delyan Angelov 8ee1667a9a
tools: fix exiting the v repl, after just Enter (regression happened in bf00ac6) 2023-08-02 10:58:31 +03:00
yuyi 1d9835f0e4
parser, cgen: fix `for i++; i<10; i++ {` (fix #18445) (#19035) 2023-08-02 10:47:52 +03:00
Turiiya 6b978a6b5a
vdoc: refactor theme files (#19024) 2023-08-02 10:46:18 +03:00
yuyi 43800a05e8
fmt: fix formatting of fn with argument comments (#19038) 2023-08-02 10:40:09 +03:00
Lucas V. Araujo ecca3b155e
net.mbedtls: add SSLListener to allow creating SSL servers (#19022) 2023-08-01 20:45:50 +03:00
yuyi 600f891d3a
checker, cgen: implement fixed array of threads wait() (#19032) 2023-08-01 20:45:00 +03:00
shove b6d6d4b037
parser: fix improper token advancement when parsing the types of struct thread type fields(fix #19029) (#19030) 2023-08-01 19:10:52 +03:00
Delyan Angelov ecf8fcd45a
ci: bump timeout-minutes: to 20, for v-compiles-os-android, gg-regressions, doom-regressions, to reduce false positives 2023-08-01 12:09:41 +03:00
Delyan Angelov 177bb30013
net: change default of the socket used by net.listen_tcp, to dualstack, even if the OS has a different default. Allow changing the listen backlog too
With this change, example vweb programs, will continue to be available to both
ipv6 and ipv4 connections from the same machine, even after doing (on linux):
`echo 1 | sudo tee /proc/sys/net/ipv6/bindv6only`

Previously, after that, vweb programs responded only to ipv6 connections, but not to ipv4 ones,
i.e. opening http://127.0.0.1:8082/ stopped working, for `v run examples/vweb/vweb_example.v` .

Note: GO web servers have the same behaviour, which is convenient for development/testing,
since it makes the programs more consistent and robust in the face of OS settings changes.
2023-08-01 11:32:08 +03:00
yuyi 367e38d7d1
parser: change fn_args() to fn_params() (#19027) 2023-08-01 07:27:53 +03:00
Turiiya def0161281
github: update issue template presets (#19026) 2023-08-01 07:25:27 +03:00
yuyi a1aca4c578
checker: fix generic struct field init recursively (related #19014) (#19025) 2023-08-01 07:20:33 +03:00
Turiiya 5061aeee64
vdoc: fix toc height (accidental height removal in 9750061) (#19023) 2023-08-01 07:11:44 +03:00
Delyan Angelov f4c2ecfaa9
crypto.sha512: make the new384/0, new512_256/0, new512_224/0 functions public 2023-08-01 06:55:41 +03:00
yuyi 9be80198fc
checker: fix generic struct field with default fn_type value (fix #19011) (#19014) 2023-07-31 21:30:12 +03:00
jacksonmowry a609d6c9d1
db.pg: add parameter syntax to docs (#19003) 2023-07-31 21:26:45 +03:00
Kim Shrier fd81bae361
net.websocket: remove unnecessary manual frees of static strings (#19009) 2023-07-31 21:23:33 +03:00
yuyi 8861538c66
ast, parser, fmt: implement inline comments (#19012) 2023-07-31 21:22:51 +03:00
Artem Yurchenko 0f861db9b0
gg: implement Android specific APK asset loading for the `create_image` function (#19015) 2023-07-31 17:40:16 +03:00
Turiiya 9750061d70
vdoc: fix scrollspy and initial keyboard navigability (#19017) 2023-07-31 17:38:25 +03:00
Delyan Angelov 81e99a2af3
term: fix vlib/term/termios/termios_test.v on windows 2023-07-31 14:22:03 +03:00
Delyan Angelov 367289a1f1
sync: fix compilation on windows 2023-07-31 11:18:12 +03:00
Delyan Angelov 2cd5b8a86d
time: reduce the diff for `v run cmd/tools/check_os_api_parity time` 2023-07-31 11:02:10 +03:00
Delyan Angelov 618961fab5
tests: reduce sensitivity/flakyness of vlib/v/slow_tests/crun_mode/crun_test.v 2023-07-31 10:58:30 +03:00
Delyan Angelov d97423d385
tools: add a test for `v -os wasm32_emscripten examples/2048` in `v test-all` 2023-07-31 10:57:57 +03:00
Delyan Angelov 30d4e25385
term: fix `v run cmd/tools/check_os_api_parity.v term`, for term.clear 2023-07-31 10:39:28 +03:00
Delyan Angelov 32114a679a
os,term.termios: add termios.set_state/2, state.disable_echo/0, use them in os.input_password, to fix `v -os wasm32_emscripten examples/2048/` 2023-07-31 10:28:45 +03:00
Delyan Angelov 37e7d5f5ae
Revert "sokol: use GLCORE33 on linux", since it is already done by a `#flag linux -DSOKOL_GLCORE33` later on
This reverts commit 7cec70e525.
2023-07-30 18:32:24 +03:00
Swastik Baranwal 8735694d13
parser: disallow declaring static functions as method receivers (#19007) 2023-07-30 06:11:11 +03:00
Turiiya 77049600e6
tests: make projects_with_c_code closer to actual projects (#19008) 2023-07-30 06:00:48 +03:00
katekyy b622dca915
builtin: fix split_nth() and rsplit_nth() on an empty delimeter (#19005) 2023-07-30 00:12:51 +03:00
Turiiya e78e468d5f
vdoc: include the project root folder, when searching for readme of `src/` (#19000) 2023-07-30 00:00:18 +03:00
Delyan Angelov 1c2b4e76dc
tests: fix diff.color_compare_strings parameter order in test files, to make analysing the results easier 2023-07-29 16:42:40 +03:00
yuyi 112a1278bb
parser, fmt: fix formatting interface method with pre-comments (#18998) 2023-07-29 15:40:45 +03:00
shove 8586f18383
checker: fix compiler crashes when passing an extra decompose parameter to a function(fix: 18995) (#18996) 2023-07-29 15:38:39 +03:00
yuyi a61a2fd328
parser: fix for_c_stmt that init with var assign (#19004) 2023-07-29 15:29:35 +03:00
Turiiya c4a679186f
examples, readme: fix typos (#18994) 2023-07-29 15:27:03 +03:00
Turiiya 490a014bf6
tools: support a toc for projects, with single exposing module, in `v doc` (#19001) 2023-07-29 15:21:15 +03:00
Delyan Angelov 4ed9703e22
ci: bump --max_time to 1731 for the performance-regressions job, to reduce the chance of false positive failures again 2023-07-29 15:18:45 +03:00
Delyan Angelov c881e7284d
cgen: allow dump(unsafe{nil}) and dump(voidptr(123)) in the same program 2023-07-29 10:14:07 +03:00
yuyi 2f2dde8ad0
ast, parser, fmt: fix formatting struct declaration with comments (fix #18982) (#18992) 2023-07-28 15:30:15 +03:00
l-m 2fa177e310
picoev: bugfixes and UB mitigation (#18991) 2023-07-28 12:37:21 +03:00
sigmaSd 2266ccecf3
readme: update web tutorial, fix code (#18989) 2023-07-28 12:36:46 +03:00
yuyi b25288338c
parser, fmt: fix formatting interface fields with pre-comments (fix #18980) (#18988) 2023-07-28 11:42:10 +03:00
Turiiya e0aba77cc5
readme: update ide-plugins section (#18990) 2023-07-28 11:20:45 +03:00
Turiiya c7f708e64d
v.help: fix typos (#18987) 2023-07-28 02:29:48 +03:00
Delyan Angelov aa3d560b05
sokol: fix `v -cc gcc ~/.vmodules/sdl/examples/sdl_opengl_and_sokol/` on Linux (add missing -lm for gcc/clang) 2023-07-28 02:27:43 +03:00
Delyan Angelov 76e3b7dff8
builder: fix `./v -os windows run examples/hello_world.v` (eliminate the "No such file or directory; code: 2" msg) 2023-07-28 01:53:57 +03:00
Delyan Angelov fe87d20f20
builder: cleanup commented cross compilation code in cc.v 2023-07-28 01:18:50 +03:00
181 changed files with 2879 additions and 1709 deletions

View File

@ -6,7 +6,7 @@ end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.v]
[*.{v,js,css}]
indent_style = tab
[*.{bat,cmd}]

View File

@ -1,7 +1,6 @@
name: 🐛 Bug Report
description: Report a bug
title: (bug report summary)
labels: Bug
labels: [Bug]
body:
- type: textarea
id: description

View File

@ -1,7 +1,6 @@
name: 🚀 Feature Request
description: Suggest an idea for this project
title: (feature request summary)
labels: Feature Request
labels: [Feature Request]
body:
- type: textarea
id: description

View File

@ -60,7 +60,7 @@ jobs:
doom-regressions:
runs-on: ubuntu-20.04
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
timeout-minutes: 10
timeout-minutes: 20
env:
VFLAGS: -cc tcc
DISPLAY: :99

View File

@ -12,7 +12,7 @@ jobs:
gg-regressions:
runs-on: ubuntu-20.04
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
timeout-minutes: 10
timeout-minutes: 20
env:
VFLAGS: -cc tcc
DISPLAY: :99

19
.github/workflows/module_docs_lint.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Code CI vlib modules
on:
push:
paths:
- '**/cmd/tools/vdoc/theme/**'
pull_request:
paths:
- '**/cmd/tools/vdoc/theme/**'
jobs:
lint-module-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check Formatting
uses: actionsx/prettier@v2
with:
args: --check cmd/tools/vdoc/theme

View File

@ -63,7 +63,7 @@ jobs:
- name: Repeat -o hw.c examples/hello_world.v
run: cmd/tools/repeat --max_time 251 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o hw.c examples/hello_world.v' . ./vmaster
- name: Repeat -o v.c cmd/v
run: cmd/tools/repeat --max_time 1701 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o v.c cmd/v' . ./vmaster
run: cmd/tools/repeat --max_time 1731 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o v.c cmd/v' . ./vmaster
misc-tooling:
runs-on: ubuntu-20.04

View File

@ -52,7 +52,7 @@ jobs:
v-compiles-os-android:
runs-on: ubuntu-20.04
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
timeout-minutes: 10
timeout-minutes: 20
steps:
- uses: actions/checkout@v3
- name: Build V

View File

@ -201,34 +201,23 @@ cd v
make
```
## Installing editor/IDE plugin
## Editor/IDE Plugins
V has plugins for many editors:
To bring IDE functions for the V programming languages to your editor, check out
[v-analyzer](https://github.com/v-analyzer/v-analyzer). It provides a
[VS Code extension](https://marketplace.visualstudio.com/items?itemName=VOSCA.vscode-v-analyzer)
and language server capabilities for other editors.
The plugin for JetBrains IDEs (IntelliJ, CLion, GoLand, etc.) also offers a great development
experience with V. You can find all features in [its documentation](https://plugins.jetbrains.com/plugin/20287-vlang/docs/syntax-highlighting.html).
Other Plugins:
- [VS Code plugin](https://github.com/vlang/vscode-vlang)
- [JetBrains IDE plugin](https://plugins.jetbrains.com/plugin/20287-vlang/docs/quick-start-guide.html)
- [Vim plugins](https://github.com/vlang/awesome-v#vim)
- [Emacs plugins](https://github.com/vlang/awesome-v#emacs)
- [Sublime Text 3 plugins](https://github.com/vlang/awesome-v#sublime-text-3)
- [Atom plugins](https://github.com/vlang/awesome-v#atom)
### IntelliSense
V has a Language Server:
[VLS](https://github.com/vlang/vls).
The VS Code plugin provides built-in support for VLS.
> **Note**
>
> VLS may be unstable at the moment.
> If you encounter any problem, please create a new
> [issue](https://github.com/vlang/vls/issues).
The plugin for JetBrains IDE (IntelliJ, CLion, GoLand, etc) at the moment is
the best choice if you want a great V development experience.
You can see all its features in
[its documentation](https://plugins.jetbrains.com/plugin/20287-vlang/docs/syntax-highlighting.html).
## Testing and running the examples
Make sure V can compile itself:

View File

@ -12,7 +12,7 @@ import term
const (
base_os = 'linux'
os_names = ['linux', 'macos', 'windows']
os_names = ['linux', 'macos', 'windows', 'freebsd', 'openbsd', 'solaris', 'termux']
skip_modules = [
'builtin.bare',
'builtin.linux_bare.old',
@ -103,7 +103,7 @@ fn (app App) gen_api_for_module_in_os(mod_name string, os_name string) string {
for s in f.stmts {
if s is ast.FnDecl {
if s.is_pub {
fn_signature := s.stringify_fn_decl(b.table, mod_name, map[string]string{})
fn_signature := b.table.stringify_fn_decl(&s, mod_name, map[string]string{})
fn_mod := s.modname()
if fn_mod == mod_name {
fline := '${fn_mod}: ${fn_signature}'

View File

@ -10,6 +10,7 @@ import v.ast
import v.token
import v.doc
import v.pref
import v.util { tabs }
const (
css_js_assets = ['doc.css', 'normalize.css', 'doc.js', 'dark-mode.js']
@ -249,27 +250,27 @@ fn (vd VDoc) gen_html(d doc.Doc) string {
version).replace('{{ light_icon }}', vd.assets['light_icon']).replace('{{ dark_icon }}',
vd.assets['dark_icon']).replace('{{ menu_icon }}', vd.assets['menu_icon']).replace('{{ head_assets }}',
if cfg.inline_assets {
'\n${tabs[0]}<style>' + vd.assets['doc_css'] + '</style>\n${tabs[0]}<style>' +
vd.assets['normalize_css'] + '</style>\n${tabs[0]}<script>' +
vd.assets['dark_mode_js'] + '</script>'
'<style>${vd.assets['doc_css']}</style>
${tabs(2)}<style>${vd.assets['normalize_css']}</style>
${tabs(2)}<script>${vd.assets['dark_mode_js']}</script>'
} else {
'\n${tabs[0]}<link rel="stylesheet" href="' + vd.assets['doc_css'] +
'" />\n${tabs[0]}<link rel="stylesheet" href="' + vd.assets['normalize_css'] +
'" />\n${tabs[0]}<script src="' + vd.assets['dark_mode_js'] + '"></script>'
'<link rel="stylesheet" href="${vd.assets['doc_css']}" />
${tabs(2)}<link rel="stylesheet" href="${vd.assets['normalize_css']}" />
${tabs(2)}<script src="${vd.assets['dark_mode_js']}"></script>'
}).replace('{{ toc_links }}', if cfg.is_multi || vd.docs.len > 1 {
modules_toc_str
} else {
symbols_toc_str
}).replace('{{ contents }}', contents.str()).replace('{{ right_content }}', if cfg.is_multi
&& vd.docs.len > 1 && d.head.name != 'README' {
'<div class="doc-toc"><ul>' + symbols_toc_str + '</ul></div>'
&& d.head.name != 'README' {
'<div class="doc-toc"><ul>${symbols_toc_str}</ul></div>'
} else {
''
}).replace('{{ footer_content }}', gen_footer_text(d, !cfg.no_timestamp)).replace('{{ footer_assets }}',
if cfg.inline_assets {
'<script>' + vd.assets['doc_js'] + '</script>'
'<script>${vd.assets['doc_js']}</script>'
} else {
'<script src="' + vd.assets['doc_js'] + '"></script>'
'<script src="${vd.assets['doc_js']}"></script>'
})
return result
}
@ -407,12 +408,12 @@ fn doc_node_html(dn doc.DocNode, link string, head bool, include_examples bool,
node_id = 'readme_${node_id}'
hash_link = ' <a href="#${node_id}">#</a>'
}
dnw.writeln('${tabs[1]}<section id="${node_id}" class="doc-node${node_class}">')
dnw.writeln('${tabs(2)}<section id="${node_id}" class="doc-node${node_class}">')
if dn.name.len > 0 {
if dn.kind == .const_group {
dnw.write_string('${tabs[2]}<div class="title"><${head_tag}>${sym_name}${hash_link}</${head_tag}>')
dnw.write_string('${tabs(3)}<div class="title"><${head_tag}>${sym_name}${hash_link}</${head_tag}>')
} else {
dnw.write_string('${tabs[2]}<div class="title"><${head_tag}>${dn.kind} ${sym_name}${hash_link}</${head_tag}>')
dnw.write_string('${tabs(3)}<div class="title"><${head_tag}>${dn.kind} ${sym_name}${hash_link}</${head_tag}>')
}
if link.len != 0 {
dnw.write_string('<a class="link" rel="noreferrer" target="_blank" href="${link}">${link_svg}</a>')

View File

@ -0,0 +1 @@
hello from readme

View File

@ -0,0 +1,3 @@
module foo
fn bar()

View File

@ -0,0 +1,4 @@
hello from readme
module foo
fn bar()

View File

@ -0,0 +1,3 @@
module foo
pub fn bar() {}

View File

@ -52,6 +52,11 @@ fn check_path(vexe string, dir string, tests []string) int {
cmd: '${os.quoted_path(vexe)} doc -comments ${os.quoted_path(program)}'
out_filename: 'main.comments.out'
)
fails += check_output(
program: program
cmd: '${os.quoted_path(vexe)} doc -readme -comments ${os.quoted_path(program)}'
out_filename: 'main.readme.comments.out'
)
total_fails += fails
if fails == 0 {
println(term.green('OK'))
@ -71,7 +76,7 @@ fn print_compare(expected string, found string) {
println(found)
println('============\n')
println('diff:')
println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected))
println(diff.color_compare_strings(diff_cmd, rand.ulid(), expected, found))
println('============\n')
}

View File

@ -0,0 +1,5 @@
{
"useTabs": true,
"printWidth": 100,
"singleQuote": true
}

View File

@ -1,6 +1,5 @@
(function() {
var html = document.getElementsByTagName('html')[0];
if (localStorage.getItem('dark-mode') === 'true') {
html.classList.add('dark');
}
(function () {
if (localStorage.getItem('dark-mode') === 'true') {
document.querySelector('html').classList.add('dark');
}
})();

File diff suppressed because it is too large Load Diff

View File

@ -1,235 +1,204 @@
(function () {
if (document.body.scrollIntoView) {
var docnav = document.querySelector('.doc-nav');
var active = docnav.querySelector('li.active');
if (active) {
active.scrollIntoView({ block: 'center', inline: 'nearest' });
}
}
setupScrollSpy();
setupMobileToggle();
setupDarkMode();
setupSearch();
setupCollapse();
const docnav = document.querySelector('.doc-nav');
const active = docnav.querySelector('li.active');
active?.scrollIntoView({ block: 'center', inline: 'nearest' });
setupMobileToggle();
setupDarkMode();
setupScrollSpy();
setupSearch();
setupCollapse();
})();
function setupScrollSpy() {
var sectionPositions = [];
var sections = document.querySelectorAll('section');
sections.forEach(function (section) {
sectionPositions.push(section.offsetTop);
});
var scrollPos = 0;
window.addEventListener('scroll', function (_) {
// Reset classes
document.querySelectorAll('.doc-toc a[class="active"]').forEach(function (link) {
link.classList.remove('active');
});
// Set current menu link as active
var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
for (var i = 0; i < sectionPositions.length; i++) {
var section = sections[i];
var position = sectionPositions[i];
if (position >= scrollPosition) {
var link = document.querySelector('.doc-toc a[href="#' + section.id + '"]');
if (link) {
link.classList.add('active');
var docToc = document.querySelector('.doc-toc');
var tocHeight = docToc.clientHeight;
var scrollTop = docToc.scrollTop;
if ((document.body.getBoundingClientRect()).top < scrollPos && scrollTop < link.offsetTop - 10) {
docToc.scrollTop = link.clientHeight + link.offsetTop - tocHeight + 10;
} else if (scrollTop > link.offsetTop - 10) {
docToc.scrollTop = link.offsetTop - 10;
}
}
break;
}
}
scrollPos = (document.body.getBoundingClientRect()).top;
});
const sections = document.querySelectorAll('section');
const sectionPositions = Array.from(sections).map((section) => section.offsetTop);
let scrollPos = 0;
window.addEventListener('scroll', () => {
const toc = document.querySelector('.doc-toc');
// Reset classes
toc.querySelectorAll('a[class="active"]').forEach((link) => link.classList.remove('active'));
// Set current menu link as active
let scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
for (const [i, position] of sectionPositions.entries()) {
if (position >= scrollPosition) {
const section = sections[i];
const link = toc.querySelector('a[href="#' + section.id + '"]');
if (link) {
link.classList.add('active');
const tocHeight = toc.clientHeight;
const scrollTop = toc.scrollTop;
if (
document.body.getBoundingClientRect().top < scrollPos &&
scrollTop < link.offsetTop - 10
) {
toc.scrollTop = link.clientHeight + link.offsetTop - tocHeight + 10;
} else if (scrollTop > link.offsetTop - 10) {
toc.scrollTop = link.offsetTop - 10;
}
}
break;
}
}
scrollPos = document.body.getBoundingClientRect().top;
});
}
function setupMobileToggle() {
var toggle = document.getElementById('toggle-menu');
toggle.addEventListener('click', function (_) {
var docNav = document.querySelector('.doc-nav');
var isHidden = docNav.classList.contains('hidden');
docNav.classList.toggle('hidden');
var search = document.querySelector('.doc-nav > .search');
console.log(search);
var searchHasResults = search.classList.contains('has-results');
if (isHidden && searchHasResults) {
search.classList.remove('mobile-hidden');
} else {
search.classList.add('mobile-hidden');
}
var content = document.querySelector('.doc-nav .content');
content.classList.toggle('hidden');
content.classList.toggle('show');
});
document.getElementById('toggle-menu').addEventListener('click', () => {
const docNav = document.querySelector('.doc-nav');
const isHidden = docNav.classList.contains('hidden');
docNav.classList.toggle('hidden');
const search = docNav.querySelector('.search');
// console.log(search);
const searchHasResults = search.classList.contains('has-results');
if (isHidden && searchHasResults) {
search.classList.remove('mobile-hidden');
} else {
search.classList.add('mobile-hidden');
}
const content = docNav.querySelector('.content');
content.classList.toggle('hidden');
content.classList.toggle('show');
});
}
function setupDarkMode() {
var html = document.getElementsByTagName('html')[0];
var darkModeToggle = document.getElementById('dark-mode-toggle');
darkModeToggle.addEventListener('click', function () {
html.classList.toggle('dark');
var isDarkModeEnabled = html.classList.contains('dark');
localStorage.setItem('dark-mode', isDarkModeEnabled);
darkModeToggle.setAttribute('aria-checked', isDarkModeEnabled)
});
// Check if css var() is supported and enable dark mode toggle
if (window.CSS && CSS.supports('color', 'var(--fake-var)')) {
darkModeToggle.style.visibility = 'unset';
}
const html = document.querySelector('html');
const darkModeToggle = document.getElementById('dark-mode-toggle');
darkModeToggle.addEventListener('click', () => {
html.classList.toggle('dark');
const isDarkModeEnabled = html.classList.contains('dark');
localStorage.setItem('dark-mode', isDarkModeEnabled);
darkModeToggle.setAttribute('aria-checked', isDarkModeEnabled);
});
}
function setupSearch() {
var searchInput = document.getElementById('search');
var onInputChange = debounce(function (e) {
var searchValue = e.target.value.toLowerCase();
var menu = document.querySelector('.doc-nav > .content');
var search = document.querySelector('.doc-nav > .search');
if (searchValue === '') {
// reset to default
menu.style.display = '';
if (!search.classList.contains('hidden')) {
search.classList.add('hidden');
search.classList.remove('has-results');
}
} else if (searchValue.length >= 2) {
// search for less than 2 characters can display too much results
search.innerHTML = '';
menu.style.display = 'none';
if (search.classList.contains('hidden')) {
search.classList.remove('hidden');
search.classList.remove('mobile-hidden');
search.classList.add('has-results');
}
// cache length for performance
var foundModule = false;
var searchModuleIndexLength = searchModuleIndex.length;
var ul = document.createElement('ul');
search.appendChild(ul);
for (var i = 0; i < searchModuleIndexLength; i++) {
// no toLowerCase needed because modules are always lowercase
var title = searchModuleIndex[i];
if (title.indexOf(searchValue) === -1) {
continue
}
foundModule = true;
// [description, link]
var data = searchModuleData[i];
var description = data[0];
var link = data[1];
var el = createSearchResult({
link: link,
title: title,
description: description,
badge: 'module',
});
ul.appendChild(el);
}
if (foundModule) {
var hr = document.createElement('hr');
hr.classList.add('separator');
search.appendChild(hr);
}
var searchIndexLength = searchIndex.length;
var results = [];
for (var i = 0; i < searchIndexLength; i++) {
var title = searchIndex[i];
if (title.toLowerCase().indexOf(searchValue) === -1) {
continue
}
// [badge, description, link]
var data = searchData[i];
var badge = data[0];
var description = data[1];
var link = data[2];
var prefix = data[3];
results.push({
badge: badge,
description: description,
link: link,
title: prefix + ' ' + title,
});
}
results.sort(function (a, b) {
if (a.title < b.title) {
return -1;
}
if (a.title > b.title) {
return 1;
}
return 0;
});
var ul = document.createElement('ul');
search.appendChild(ul);
for (var i = 0; i < results.length; i++) {
var result = results[i];
var el = createSearchResult(result);
ul.appendChild(el);
}
}
});
searchInput.addEventListener('input', onInputChange);
const searchInput = document.getElementById('search');
const onInputChange = debounce((e) => {
const searchValue = e.target.value.toLowerCase();
const docNav = document.querySelector('.doc-nav');
const menu = docNav.querySelector('.content');
const search = docNav.querySelector('.search');
if (searchValue === '') {
// reset to default
menu.style.display = '';
if (!search.classList.contains('hidden')) {
search.classList.add('hidden');
search.classList.remove('has-results');
}
} else if (searchValue.length >= 2) {
// search for less than 2 characters can display too much results
search.innerHTML = '';
menu.style.display = 'none';
if (search.classList.contains('hidden')) {
search.classList.remove('hidden');
search.classList.remove('mobile-hidden');
search.classList.add('has-results');
}
// cache length for performance
let foundModule = false;
const ul = document.createElement('ul');
search.appendChild(ul);
for (const [i, title] of searchModuleIndex.entries()) {
// no toLowerCase needed because modules are always lowercase
if (title.indexOf(searchValue) === -1) {
continue;
}
foundModule = true;
// [description, link]
const data = searchModuleData[i];
const el = createSearchResult({
badge: 'module',
description: data[0],
link: data[1],
title: title,
});
ul.appendChild(el);
}
if (foundModule) {
const hr = document.createElement('hr');
hr.classList.add('separator');
search.appendChild(hr);
}
let results = [];
for (const [i, title] of searchIndex.entries()) {
if (title.toLowerCase().indexOf(searchValue) === -1) {
continue;
}
// [badge, description, link]
const data = searchData[i];
results.push({
badge: data[0],
description: data[1],
link: data[2],
title: data[3] + ' ' + title,
});
}
results.sort((a, b) => (a.title < b.title ? -1 : a.title > b.title ? 1 : 0));
const ul_ = document.createElement('ul');
search.appendChild(ul_);
results.forEach((result) => {
const el = createSearchResult(result);
ul_.appendChild(el);
});
}
});
searchInput.addEventListener('input', onInputChange);
}
function createSearchResult(data) {
var li = document.createElement('li');
li.classList.add('result');
var a = document.createElement('a');
a.href = data.link;
a.classList.add('link');
li.appendChild(a);
var defintion = document.createElement('div');
defintion.classList.add('definition');
a.appendChild(defintion);
if (data.description) {
var description = document.createElement('div');
description.classList.add('description');
description.textContent = data.description;
a.appendChild(description);
}
var title = document.createElement('span');
title.classList.add('title');
title.textContent = data.title;
defintion.appendChild(title);
var badge = document.createElement('badge');
badge.classList.add('badge');
badge.textContent = data.badge;
defintion.appendChild(badge);
return li;
const li = document.createElement('li');
li.classList.add('result');
const a = document.createElement('a');
a.href = data.link;
a.classList.add('link');
li.appendChild(a);
const defintion = document.createElement('div');
defintion.classList.add('definition');
a.appendChild(defintion);
if (data.description) {
const description = document.createElement('div');
description.classList.add('description');
description.textContent = data.description;
a.appendChild(description);
}
const title = document.createElement('span');
title.classList.add('title');
title.textContent = data.title;
defintion.appendChild(title);
const badge = document.createElement('badge');
badge.classList.add('badge');
badge.textContent = data.badge;
defintion.appendChild(badge);
return li;
}
function setupCollapse() {
var dropdownArrows = document.querySelectorAll('.dropdown-arrow');
for (var i = 0; i < dropdownArrows.length; i++) {
var dropdownArrow = dropdownArrows[i];
dropdownArrow.addEventListener('click', function (e) {
var parent = e.target.parentElement.parentElement.parentElement;
parent.classList.toggle('open');
});
}
const dropdownArrows = document.querySelectorAll('.dropdown-arrow');
dropdownArrows.forEach((arrow) => {
arrow.addEventListener('click', (e) => {
const parent = e.target.parentElement.parentElement.parentElement;
parent.classList.toggle('open');
});
});
}
function debounce(func, timeout) {
var timer;
return (...args) => {
const next = () => func(...args);
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(next, timeout > 0 ? timeout : 300);
}
let timer;
return (...args) => {
const next = () => func(...args);
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(next, timeout > 0 ? timeout : 300);
};
}
document.addEventListener('keypress', (ev) => {
if (ev.key == '/') {
let search = document.getElementById('search');
ev.preventDefault();
search.focus();
}
if (ev.key == '/') {
const search = document.getElementById('search');
ev.preventDefault();
search.focus();
}
});

View File

@ -1,19 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View File

@ -1,63 +1,72 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title }} | vdoc</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Jost:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap"
rel="stylesheet"
/>
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png" />
<link rel="manifest" href="site.webmanifest" />
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#5bbad5" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#ffffff" />
{{ head_assets }}
</head>
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }} | vdoc</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Jost:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap" rel="stylesheet">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="manifest" href="site.webmanifest">
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
{{ head_assets }}
</head>
<body>
<div><a id="skip-to-content-link" href="#main-content">Skip to content</a></div>
<div id="page">
<header class="doc-nav hidden">
<div class="heading-container">
<div class="heading">
<div class="info">
<div class="module">{{ head_name }}</div>
<div class="toggle-version-container">
<span>{{ version }}</span>
<div id="dark-mode-toggle" role="switch" aria-checked="false" aria-label="Toggle dark mode">{{ light_icon }}{{ dark_icon }}</div>
</div>
{{ menu_icon }}
</div>
<input type="text" id="search" placeholder="Search... (beta)" autocomplete="off">
</div>
</div>
<nav class="search hidden"></nav>
<nav class="content hidden">
<ul>
{{ toc_links }}
</ul>
</nav>
</header>
<div class="doc-scrollview" id="main-content">
<div class="doc-container">
<div class="doc-content">
{{ contents }}
<div class="footer">
{{ footer_content }}
</div>
</div>
{{ right_content }}
</div>
</div>
</div>
{{ footer_assets }}
<script async src="search_index.js"></script>
</body>
<body>
<div><a id="skip-to-content-link" href="#main-content">Skip to content</a></div>
<div id="page">
<header class="doc-nav hidden">
<div class="heading-container">
<div class="heading">
<div class="info">
<div class="module">{{ head_name }}</div>
<div class="toggle-version-container">
<span>{{ version }}</span>
<div
id="dark-mode-toggle"
role="switch"
aria-checked="false"
aria-label="Toggle dark mode"
>
{{ light_icon }}{{ dark_icon }}
</div>
</div>
{{ menu_icon }}
</div>
<input type="text" id="search" placeholder="Search... (beta)" autocomplete="off" />
</div>
</div>
<nav class="search hidden"></nav>
<nav class="content hidden">
<ul>
{{ toc_links }}
</ul>
</nav>
</header>
<div class="doc-scrollview" id="main-content">
<div class="doc-container">
<div class="doc-content">
{{ contents }}
<div class="footer">{{ footer_content }}</div>
</div>
{{ right_content }}
</div>
</div>
</div>
{{ footer_assets }}
<script async src="search_index.js"></script>
</body>
</html>

View File

@ -91,24 +91,24 @@ select {
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
[type='button']::-moz-focus-inner,
[type='reset']::-moz-focus-inner,
[type='submit']::-moz-focus-inner {
border-style: none;
padding: 0;
}
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
[type='button']:-moz-focusring,
[type='reset']:-moz-focusring,
[type='submit']:-moz-focusring {
outline: 1px dotted ButtonText;
}
@ -133,23 +133,23 @@ textarea {
overflow: auto;
}
[type="checkbox"],
[type="radio"] {
[type='checkbox'],
[type='radio'] {
box-sizing: border-box;
padding: 0;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
[type='number']::-webkit-inner-spin-button,
[type='number']::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
[type='search'] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="search"]::-webkit-search-decoration {
[type='search']::-webkit-search-decoration {
-webkit-appearance: none;
}

View File

@ -16,7 +16,6 @@ const (
allowed_formats = ['md', 'markdown', 'json', 'text', 'stdout', 'html', 'htm']
vexe = os.getenv_opt('VEXE') or { @VEXE }
vroot = os.dir(vexe)
tabs = ['\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t']
)
enum OutputType {
@ -233,6 +232,9 @@ fn (vd VDoc) get_readme(path string) string {
}
}
if fname == '' {
if path.all_after_last(os.path_separator) == 'src' {
return vd.get_readme(path.all_before_last(os.path_separator))
}
return ''
}
readme_path := os.join_path(path, '${fname}.md')

View File

@ -312,7 +312,7 @@ fn run_repl(workdir string, vrepl_prefix string) int {
if line == '' && oline.ends_with('\n') {
continue
}
if line.len <= -1 || line == '' || line == 'exit' {
if line.len <= -1 || line == 'exit' {
break
}
if exit_pos := line.index('exit') {

View File

@ -180,6 +180,15 @@ fn get_all_commands() []Command {
okmsg: 'V can compile 2048 with -skip-unused.'
rmfile: 'examples/2048/2048'
}
if _ := os.find_abs_path_of_executable('emcc') {
res << Command{
line: '${vexe} -os wasm32_emscripten examples/2048'
okmsg: 'V can compile 2048 with -os wasm32_emscripten, using emcc.'
rmfile: 'examples/2048/2048'
}
} else {
println('> emcc not found, skipping `v -os wasm32_emscripten examples/2048`.')
}
res << Command{
line: '${vexe} -skip-unused -live examples/hot_reload/bounce.v'
okmsg: 'V can compile the hot code reloading bounce.v example with both: -skip-unused -live'

View File

@ -52,7 +52,7 @@ fn check_path(vexe string, dir string, tests []string) int {
println(found)
println('============\n')
println('diff:')
println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected))
println(diff.color_compare_strings(diff_cmd, rand.ulid(), expected, found))
println('============\n')
nb_fail++
} else {

View File

@ -1,150 +1,148 @@
# Serve
# JS DOM Cube
This project has a no dependence serve in `./server.js` path.
That can be run with `node` command after build.
## Compiling
or just run: `npm run start`
To install node, you can access node [download page](https://nodejs.org/en/download/)
or [package manager](https://nodejs.org/en/download/package-manager)
Drawing with mouse events using DOM API. Adopted from MDN examples.
# Compiling
```
v -b js_browser examples/js_dom_cube/cube.js.v
```
Drawing with mouse events using DOM API. Adopted from MDN examples.
Then you can open `index.html` with your favourite browser.
# Serve examples
Then you can open `index.html` in your favorite browser.
### JS server
After run `npm init -y` code and genared `./package.json`
You can put `start` and `build` at script in jason leaf.
`path './package.json'`
```json
"scripts": {
"start": "npm run build && node server.js",
"build":"v -b js_browser cube.js.v"
},
## Serve Examples
### JS Server
> **NOTE**\
> The JS server example in the following steps requires Node.js.
> To install Node, please refer to the [download page](https://nodejs.org/en/download/)
> or the installation via your operating systems [package manager](https://nodejs.org/en/download/package-manager).
Initialize the example as a Node project
```
here is the pure javascript server code
`path './server.js'`
cd examples/js_dom_cube/
npm init -y
```
Add a `start` and `build` script to the generated `./package.json` file.
```json
"scripts": {
...
"start": "npm run build && node server.js",
"build": "v -b js_browser cube.js.v"
},
```
Below is an example of a Node.js server without external dependencies.
You can use it for `./server.js`.
```javascript
const http = require("http");
const fs = require("fs");
const http = require('http');
const fs = require('fs');
var path = require('path');
const host = "localhost";
const host = 'localhost';
const port = 3000;
const reqListener = function (req, res) {
console.log('[route] - ', req.url);
console.log('[route] - ', req.url);
var filePath = '.' + req.url;
if (filePath == './') {
filePath = './index.html';
}
var filePath = '.' + req.url;
if (filePath == './') {
filePath = './index.html';
}
var extname = String(path.extname(filePath)).toLowerCase();
var mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.wasm': 'application/wasm'
};
var extname = String(path.extname(filePath)).toLowerCase();
var mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.wasm': 'application/wasm',
};
var contentType = mimeTypes[extname] || 'application/octet-stream';
var contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, function(error, content) {
if (error) {
if(error.code == 'ENOENT') {
fs.readFile('./404.html', function(error, content) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
});
}
else {
res.writeHead(500);
res.end('Sorry, check with the site admin for error: '+error.code+' ..\n');
}
}
else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
fs.readFile(filePath, function (error, content) {
if (error) {
if (error.code == 'ENOENT') {
fs.readFile('./404.html', function (error, content) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
});
} else {
res.writeHead(500);
res.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n');
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
};
const server = http.createServer(reqListener);
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`);
console.log(`Server is running on http://${host}:${port}`);
});
```
This project has a no dependence serve in `./server.js` path.
That can be run with `node` command after build.
or just run: `npm run start`
To install node, you can access node [download page](https://nodejs.org/en/download/)
or [package manager](https://nodejs.org/en/download/package-manager)
Now you can build and run the project with the added scripts.
```sh
npm run build
npm run start
```
$ cd examples/js_dom_draw/
$ npm run build
```
### V server
```v ignore
The example below uses `vweb` to serve the project.
```v
module main
import vweb
import os
const (
http_port = 3001
http_port = 3001
)
struct App {
vweb.Context
vweb.Context
}
fn main() {
vweb.run(new_app(), http_port)
vweb.run(new_app(), http_port)
}
pub fn (mut app App) before_request() {
// This build server json files
os.execute_or_panic('v -b js_browser cube.js.v ')
// Build the cube.js javascript file
os.execute_or_panic('v -b js_browser cube.js.v ')
}
fn new_app() &App {
mut app := &App{}
app.serve_static('/favicon.ico', 'favicon.ico')
app.serve_static('/cube.js', 'cube.js')
app.mount_static_folder_at(os.resource_abs_path('.'), '/')
return app
mut app := &App{}
app.serve_static('/favicon.ico', 'favicon.ico')
app.serve_static('/cube.js', 'cube.js')
app.mount_static_folder_at(os.resource_abs_path('.'), '/')
return app
}
['/'; get]
pub fn (mut app App) controller_get_all_task() vweb.Result {
file :=os.read_file('./index.html') or { panic(err) }
return app.html(file)
file := os.read_file('./index.html') or { panic(err) }
return app.html(file)
}
```
```

View File

@ -1,140 +1,150 @@
Drawing with mouse events using DOM API. Adopted from MDN examples.
# JS DOM Draw
# Compiling
```
Drawing with mouse events using the DOM API. Adopted from MDN examples.
## Compiling
```sh
v -b js_browser examples/js_dom_draw/draw.js.v
```
Then you can open `index.html` with your favourite browser.
# Serve examples
Then you can open `index.html` in your favorite browser.
### JS server
After run `npm init -y` code and genared `./package.json`
You can put `start` and `build` at script in jason leaf.
`path './package.json'`
```json
"scripts": {
"start": "npm run build && node server.js",
"build":"v -b js_browser draw.js.v"
},
## Serve Examples
### JS Server
> **NOTE**\
> The JS server example in the following steps requires Node.js.
> To install Node, please refer to the [download page](https://nodejs.org/en/download/)
> or the installation via your operating systems [package manager](https://nodejs.org/en/download/package-manager).
Initialize the example as a Node project
```
here is the pure javascript server code
`path './server.js'`
cd examples/js_dom_draw/
npm init -y
```
Add a `start` and `build` script to the generated `./package.json` file.
```json
"scripts": {
...
"start": "npm run build && node server.js",
"build": "v -b js_browser draw.js.v"
},
```
Below is an example of a Node.js server without external dependencies.
You can use it for `./server.js`.
```javascript
const http = require("http");
const fs = require("fs");
const http = require('http');
const fs = require('fs');
var path = require('path');
const host = "localhost";
const host = 'localhost';
const port = 3000;
const reqListener = function (req, res) {
console.log('[route] - ', req.url);
console.log('[route] - ', req.url);
var filePath = '.' + req.url;
if (filePath == './') {
filePath = './index.html';
}
var filePath = '.' + req.url;
if (filePath == './') {
filePath = './index.html';
}
var extname = String(path.extname(filePath)).toLowerCase();
var mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.wasm': 'application/wasm'
};
var extname = String(path.extname(filePath)).toLowerCase();
var mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.wasm': 'application/wasm',
};
var contentType = mimeTypes[extname] || 'application/octet-stream';
var contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, function(error, content) {
if (error) {
if(error.code == 'ENOENT') {
fs.readFile('./404.html', function(error, content) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
});
}
else {
res.writeHead(500);
res.end('Sorry, check with the site admin for error: '+error.code+' ..\n');
}
}
else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
fs.readFile(filePath, function (error, content) {
if (error) {
if (error.code == 'ENOENT') {
fs.readFile('./404.html', function (error, content) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
});
} else {
res.writeHead(500);
res.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n');
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
};
const server = http.createServer(reqListener);
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`);
console.log(`Server is running on http://${host}:${port}`);
});
```
This project has a no dependence serve in `./server.js` path.
That can be run with `node` command after build.
or just run: `npm run start`
To install node, you can access node [download page](https://nodejs.org/en/download/)
or [package manager](https://nodejs.org/en/download/package-manager)
Now you can build and run the project with the added scripts.
```sh
npm run build
npm run start
```
$ cd examples/js_dom_draw/
$ npm run build
```
### V server
```v ignore
The example below uses `vweb` to serve the project.
```v
module main
import vweb
import os
const (
http_port = 3001
http_port = 3001
)
struct App {
vweb.Context
vweb.Context
}
fn main() {
vweb.run(new_app(), http_port)
vweb.run(new_app(), http_port)
}
pub fn (mut app App) before_request() {
// This build server json files
os.execute_or_panic('v -b js_browser draw.js.v ')
// Build the draw.js javascript file
os.execute_or_panic('v -b js_browser draw.js.v ')
}
fn new_app() &App {
mut app := &App{}
app.serve_static('/favicon.ico', 'favicon.ico')
app.serve_static('/draw.js', 'draw.js')
app.mount_static_folder_at(os.resource_abs_path('.'), '/')
return app
mut app := &App{}
app.serve_static('/favicon.ico', 'favicon.ico')
app.serve_static('/draw.js', 'draw.js')
app.mount_static_folder_at(os.resource_abs_path('.'), '/')
return app
}
['/'; get]
pub fn (mut app App) controller_get_all_task() vweb.Result {
file :=os.read_file('./index.html') or { panic(err) }
return app.html(file)
file := os.read_file('./index.html') or { panic(err) }
return app.html(file)
}
```
```

View File

@ -1,35 +1,57 @@
# JS DOM Benchmark Chart
![image](https://user-images.githubusercontent.com/63821277/186010833-2ea36f3a-4738-4025-9b23-ac62afe74b81.png)
# To run app
## From root
- run typescript project
`npm i --prefix examples/js_dom_draw_bechmark_chart/typescript_vanilla_typeorm`
`npm run start:dev --prefix examples/js_dom_draw_bechmark_chart/typescript_vanilla_typeorm`
## Running the App
- run v project
`v run examples/js_dom_draw_bechmark_chart/v_vweb_orm `
> **NOTE**\
> The following steps require Node.js.
> To install Node, please refer to the [download page](https://nodejs.org/en/download/)
> or the installation via your operating systems [package manager](https://nodejs.org/en/download/package-manager).
- running v chart
`cd examples/js_dom_draw_bechmark_chart/chart && v run .`
The steps below assume that your current directory path is the examples project directory.
Dockerfile
[docker build]=> Docker image
[docker run]=> Docker container
```
cd examples/js_dom_draw_bechmark_chart
```
`sudo docker build -t <name> .`
Execute the following commands in separate terminal instances.
`sudo docker run --name <container name> --interactive --tty --publish 3001:3001 <name>`
Run the Benchmarks Typescript Part
`v run .`
```sh
npm i --prefix typescript_vanilla_typeorm
npm run start:dev --prefix typescript_vanilla_typeorm
```
A message like `[Vweb] Running app on http://localhost:3001/` should appear
Run the Benchmarks V Part
`exit`
```sh
v run v_vweb_orm
```
# To implement new benchmarks in v
Run the Chart
In `examples/js_dom_draw_bechmark_chart/v_vweb_orm/src/main.v` path
Create a route returning a `Response` struct like:
```
cd chart/ && v run .
```
## Dockerfile
> [docker build] => Docker image\
> [docker run] => Docker container
```sh
sudo docker build -t <name> .
sudo docker run --name <container name> --interactive --tty --publish 3001:3001 <name>
v run .
# A message like `[Vweb] Running app on http://localhost:3001/` should appear
exit
```
## Implementing New Benchmarks in V
In `v_vweb_orm/src/main.v`, create a route that returns a `Response` struct.
```v ignore
['/sqlite-memory/:count']
@ -65,18 +87,17 @@ pub fn (mut app App) sqlite_memory(count int) vweb.Result {
}!
response := Response{
insert: insert_stopwatchs
@select:select_stopwatchs
update: update_stopwatchs
insert: insert_stopwatchs
@select: select_stopwatchs
update: update_stopwatchs
}
return app.json(response)
}
```
In `examples/chart/services.v` path
Create a service to request the benchmarks data by http
Decode the info to `FrameworkBenchmarkResponse`
In `chart/main.v`, create a service to request the benchmark data and decode the response as
`FrameworkBenchmarkResponse`.
```v ignore
fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
url := 'http://localhost:3000/sqlite-memory/${benchmark_loop_length}'
@ -86,26 +107,13 @@ fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
}
```
In `examples/chart/main.v` path
Create a service to request the benchmarks data by http
Decode the info to `FrameworkBenchmarkResponse`
```v ignore
fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
url := 'http://localhost:3000/sqlite-memory/${benchmark_loop_length}'
res := http.get(url) or { panic(err) }
framework_benchmark_response := json.decode(FrameworkBenchmarkResponse, res.body)!
return framework_benchmark_response
}
```
Then, update:
`insert_framework_benchmark_times()`;
`select_framework_benchmark_times()`;
`update_framework_benchmark_times()`.
with the new function
Then update `insert_framework_benchmark_times()`, `select_framework_benchmark_times()` and
`update_framework_benchmark_times()` to include the `numbers := FrameworkPlatform{` for the newly
added function.
## Roadmap
# ROADMAP
02/09/2022
- [ ] select bench (easy)
- [ ] vsql (easy)

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIUTbcFMmB84wg6eqDRJbmo49aOTdMwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMzA3MzAxNzM0MThaGA8yMDUw
MTIxNDE3MzQxOFowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBANPfvg3G/3+j2NX5qDf0gw9iSnCiUa1T1inxlnfP
vMVINDkH22yUSeValyuIrpF94m23ANo0yOXQJxbIt8PbwaRYTq1EzxlGkkXUHob3
m1qJLH1qLacJeLMPj3J7kUXVWL65Qb7d2gtwMvegJ5I5U4ntLjXAmIV4z4PpZ2tP
MsERacj/alb0EDS77P4JcbRzYvP/3FyFokel5TF/nLV3hXc5Eu6LjCzbEEus1MLd
rgcpODUlw8Gf0M0nAjxijVpXAVo6XYRQ/00+zjPaKxjtQ/ds/O7zRTNxnUVvh1oH
Pnif9rkVBLkVjmSU/C7jvAKqrWPU9b24hXpnfSIirkn3tO8CAwEAAaNTMFEwHQYD
VR0OBBYEFPx8Ivgj5Gi4XyHFZ/zGgZU4kGc7MB8GA1UdIwQYMBaAFPx8Ivgj5Gi4
XyHFZ/zGgZU4kGc7MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
AJYSckwJSZlj8baEMvAJLs55Bm5wR1QZaj7mz8tBxK8zd9PdW3fTebil6jtGLpXT
CHi+vaa5HsM2QXnYaZCSlawD3WWZ+LZ9lJVuWC+iWfRq6TC/gEd+3zCE70CeeAAu
0pZC2Luvvgm5a6qfKoA4lEvlB2Yr0pX2GhXYOGvIeSMWpohKyKmiJEi83kJvzjnl
BsFIR6FB1wO2+nrfLCzmjwPQx0ie2h+fPwf5Y2C0pPBYVwXpP94EEZW+lQgPXx5I
6X8HPVNMtu4lToe746ctQlA4YDwge5mmiGUgF95Y3/O9Z2vjPqeN826oR89YFFZF
JFtrrBskGW5fOzKOXLc96pE=
-----END CERTIFICATE-----

View File

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEEzCCAvsCFG64Q2g46jZb3kRbDOJWX/BwjSp5MA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMjMwNzMwMTczNDQzWhgPMjA1MDEyMTQx
NzM0NDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQDqDmHNMesBQ6S/ZU+xW4sO18Q+WfvXEaMdEfN5D8wyazP3
mA7VTsNjliHrLFDiaTX9dR9Js+SwqmLpZTZoxBzn6wDuuM9fswvISnVERgZZdFas
lkgci4iXVE2TREEqh6Ak4CAUyGiBhHm1CaT7txvq7wTghs+cgDR5hItK7EpxD7gv
jc1sNco9Ha1GecUB0L4fCmp3ss88vvDU4ta4eLTsW/SZbTKRMawih4hp00d0v83s
Of5iIP6kWsM9X5Oe2Fm5XaObMlCdWHIBP2aB5i2ZqYUKTl8uKExpeobcsmpvHiSb
tAAaeFo/5shyCAXx/i55KYA2oRm71XeIBnllIBMEfKPV3AReO6p+MZFnioPxUWY0
gWqlSzsoLJ6NxHYWeC15OQhKQ6jEO7u3SAivacG5VVEywQ7EiY3b+ncwcZt9QK8q
UckwwnbWHZJwJcp0vHj3/Mmvawm1dWR3CVauFW3ze/l3Ik92wJBDkULhv6r07zfv
SlL2Am7+wPWfeOomx+Kh/rnGcXATcH17dVFH/mjhTjclOuM38e7oGoQhm9lZ9kaD
wIuu1X0+XutuY55uze9yVY9qRSIJraBuZ9mreVIVj9FG0kpVplrTr7oBlGA1Nc3i
1IuilE36T4qmP50WzJ6Yy38+J7My23bUyyOXIFhX/LTpPVjhZq5tVH+WmmqW0wID
AQABMA0GCSqGSIb3DQEBCwUAA4IBAQAbD+EVc4Ev7uXKUQV0s3nETp2odz1G8eZ/
drAVnWJpZEeWW98ZeVfyYglqWc9G8McYpiKeac9WF+gga8F2Cn3RjMvufqr0Ggcy
byytgJeLolukhTV/JJk8o+CUAB2xgk8+DVEiZ+7G4L/4V613VmL1B+jRHWknO/Js
uArppuSduvmkakWOGMBGLUPUcep/vIepHByjOeq1czsdrsLokjBXjMAwXAVRSkBs
mazD9yK95R5oG0KDmIPpfDddwvp7Xq4t3pTtMwXPYaDG+sPovsGsGYRkTnouOlKh
ae4/jRb8ut9AqOxZRUsBzT8MJXg4cFec8qrhPe3abzxN4amqOxlj
-----END CERTIFICATE-----

View File

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,26 @@
No extensions in certificate
-----BEGIN CERTIFICATE-----
MIIEOTCCAyECFG64Q2g46jZb3kRbDOJWX/BwjSp4MA0GCSqGSIb3DQEBCwUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMjMwNzMwMTczNDE4WhgPMjA1MDEyMTQx
NzM0MThaMGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRQwEgYD
VQQHDAtMb3MgQW5nZWxlczEdMBsGA1UECgwUQ2F0YWx5c3QgRGV2ZWxvcG1lbnQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBAKUcJ5cizbhreUlC0plQngCeE+/ysZJo8TmnhEF4cFnTVCHmvzz7f5w7/Zma
4maRzE3KT52qSA2PkX6Wr9RgnM93K93a3dfiUHaZ+DbWFnb1w/gp7TG5bgvwfjcb
KVnkP+BIMbT90kQrLI0H89LrouvCHDvl74EvAdyYgupLTdjZ5Q5Xe9P5rUhLajw6
iN8+NtfrQh2hDOWnbg9nQK/zjIVvvvjMQOUzda9Rq4ViAphiLNufojQhHJrlIpkP
oR+YENiDXRcaire5RVWjzfoQGDbTJLJL8fNV1HMjJArUuCg8yIyL1wooe+XWqscg
MzJoiCjSdai5zTF+lzcBLrm0olqB7YDCHS3x3K4C3DDRSoyFSEHRQpbSQbc6jTo6
TuWcC9o/5fIMzzHrahqoRZG7syFyHYNtezhsFobqMX4E15gV6tBf6CMpTlXMH3ss
DreZl900n1UcNtp7aQw2JIdRrLMW2I6UAit1o/FBYjkg/QCqPL7lw1nv0COraI74
CU+I7opYJJgEalOkZciapB6ARMgWD1/J9qO4q98H0jETP1bh78lwLPxRe1W5fukD
YCazJONIt4Bgdff8C2r+KhEoWQxK5VnjIdbL9E1nxscPr/4U77siCmHKdPINCrsD
CWqxUHiuyJmkw9NCrerZoIxTBFAUc+sdibvq1M528jf1IvXXAgMBAAEwDQYJKoZI
hvcNAQELBQADggEBAGoxRyyY+YraVOlFMzmyf+TeCQVibOJvKmY/HUjqCujgoj6o
7UwYDAPyfzuVerDj2IzJ9bFB818iOIQUaO8Gw70EOzDifZFCm9/pET3SD7aGd4Kk
DjCbjml/MNidVezPXNcdAM+XJ56jd2owk/pB4jaw3bkNcmn0aSnFg421fZibrTcS
VRPCHIvV8gSqJk9ENO5EGIGU1VmTR909aIYB2fYyyW/1fyP/gn7d1Afy8CimZ1uD
mUl5qQ5/CY378MmnODiGhsHJeH+ws77yLPwnh8eVtISwYMu9qfNRYFnotK7a5mxU
CWpoSR77NmCUCQOarzb34soL2zZlIK9Lx+4VQPo=
-----END CERTIFICATE-----

View File

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEApRwnlyLNuGt5SULSmVCeAJ4T7/KxkmjxOaeEQXhwWdNUIea/
PPt/nDv9mZriZpHMTcpPnapIDY+Rfpav1GCcz3cr3drd1+JQdpn4NtYWdvXD+Cnt
MbluC/B+NxspWeQ/4EgxtP3SRCssjQfz0uui68IcO+XvgS8B3JiC6ktN2NnlDld7
0/mtSEtqPDqI3z421+tCHaEM5aduD2dAr/OMhW+++MxA5TN1r1GrhWICmGIs25+i
NCEcmuUimQ+hH5gQ2INdFxqKt7lFVaPN+hAYNtMkskvx81XUcyMkCtS4KDzIjIvX
Cih75daqxyAzMmiIKNJ1qLnNMX6XNwEuubSiWoHtgMIdLfHcrgLcMNFKjIVIQdFC
ltJBtzqNOjpO5ZwL2j/l8gzPMetqGqhFkbuzIXIdg217OGwWhuoxfgTXmBXq0F/o
IylOVcwfeywOt5mX3TSfVRw22ntpDDYkh1GssxbYjpQCK3Wj8UFiOSD9AKo8vuXD
We/QI6tojvgJT4juilgkmARqU6RlyJqkHoBEyBYPX8n2o7ir3wfSMRM/VuHvyXAs
/FF7Vbl+6QNgJrMk40i3gGB19/wLav4qEShZDErlWeMh1sv0TWfGxw+v/hTvuyIK
Ycp08g0KuwMJarFQeK7ImaTD00Kt6tmgjFMEUBRz6x2Ju+rUznbyN/Ui9dcCAwEA
AQKCAgA9xjLp0RO3FD7ksiOpSQhUotBCzkKxzKG0OIC7Hhyq/u5TYMncPxyXj7pq
ZhCe353Y3QC8tKEQsc511lsi0qLY3HWFJAYsZ3hDZ4f+vErbZ0hS6RzdpcsOnIQc
igUGpOdhOqGeXfj1mFGq0nbfS1pBava1UmoxoyzHJCiXEGWn5J5Wp1SlEp1KlyzA
LAZZwCU008iA3Wi9487B5JfHPRAuPIju/TyqhH5bgerylKDz8odmBGvjpR/WtDQl
oDtgXryuxTdnFX8hDihqykaecLcejBEGxHNZ35sFGPi7NKtSIqvGKevi2RLCA3cR
2XJOQd3vqA5telbTVdGturuIr5SuPmZgSTQM4PnbuzmwFaXZH6REBLsRkDYHUQsE
nGKyh81Out2taBeJUoJ+CCuGmVsWU3UfRhOHMatSi+aasK3P1My1H2uCYzIpaUBG
rQKOqJsuwQsAejkZ0b3D8s6Y1BoQey7qmwlNhmZ4pw0tdQsOyvht2ZwmU6U0cTXu
LtaqwSWC6oz5yepVFGpF6FfuPHD7UrznGuFfiyONIxExqW5yYF+JjUdYg3At2kiX
Pv4IpfSbXu9Fivbw90zWGc+RrmtXmf3ZzAW4nD9tHNpz9EPDfYIiW3vYnYxWbWX8
oVqIz2/FLrOa+c0ZO0TBCHY0NFQ0tz1WCjz1Nc0sDbGuQsngAQKCAQEAzlkndsaj
TIlBWveSd4dmGKTdKyo1xKeE1FhHw5YoOX3xjqrPLTUS9Dy04R8LGRQmceUyuGmL
JBk6Ab0lAxuT4YpADBh8uXn5xBI/BjETby3x0511Dmfi8m0mwgGYJeWk9vPACTvI
KLzvDF8FjLw/AMjpG62oHnGvVUTfwR5fw7o32yLkVZ5dBVXLp5z0wnT6lzICIzCr
sQNpaNBoUkSNLQYvBsD97fJt2FzfLb3QWIf4ld6joP1236LfanJTOmYofS4RkC6h
Rkg6onlSEAvOXCKggRAX1XlHn73tehkMpndR/9xpfmO+E5Tz4Sx/WTiwXVKlJ41/
2HUcGkTJOlRf1wKCAQEAzNbDim/JJw0hw/vjGPgzUC8XC4Ciavxs9YJQhIKgtdRA
TosmJ3bb9UzL+6us6+/rECMSXYHLS6NijHuhAvtn0jCEgeja/JpYkkQG+MAJHN0a
8XwjUce938T2PGZMxdk3Kdbhpgvfq5OUELPOk2mPO/YKOJDPIwSqZJBwRXvVYPkl
ImJ14wodjnKwVLCQWKw5XonoDWs8o6XeCkTN56ZjpzHUvptKiIdOK5GcLBwI+CrP
RBExqwtMQkR9ecQmhaiocjNb7roH0GzqTPMTdNP26ZqS2B8/QFpsbyzKyRgEvCm0
BXHkVmaQ4PC+tGO3AOQAe7klzwgvLimN1Q8HyCtaAQKCAQEAg+9PI0uId9Q+nFo1
JQXGirVG0GWRsWZmsJqtb+nfWDslqtGd28rWjqEOCe6eWu+eUS55yp15IKCcjSYR
tzX3zLpnjxRNEw5hWzNLZrsUMP8QYvyHLqnP2q9dm6gHTxvQ6TEatQyrQxjiQ2ey
FbT7F5ZeLZtQJf8MWxnJcyHnmy7CrfNWSUQTN+kOaOIbQQYof2mzIirpbCnBSQoP
2aIJHiOZB9l3wp9CCpf+/rEhuKlfkPukZbgKPJ1X+iiU/H77HmbJRgX6igR+sQmf
JbFWxWRCeaL/ijecSw/V+j5v7zPVkyGrtesySjTv5iZcWoC7iz/fZzW663yddlJK
02fFSwKCAQBTqIroKUuQJW7a6i8P7Z6XawQQcJLk+v9NLdHQrMESQgOZkH8esw6W
mqzctnrDSZNJXemMQwxScgI3ue5Cl4cJc0NLA10cubTe1+W5BkUygqMUaUzLg7Zq
g7jFZkqIq3Q6JEa4WDUbkARy5dzCm+Qh6xS1kX7noGou9EbGOhMlrduatXfMKD92
BCU8EXiCnqQ3lj8t69QySfXrX7pwl6YvjMyEpEvGguxMIwYThcesA1/vPs54Ov8E
OZC9gHzzLbTOH2e2kkfKuhDfKI+TsVYwhi7fEbP1hniu1y5i/upAJxAdASzulKkr
FWftqKP/Ox9vaGimq4MJaXNBxwe4muwBAoIBAGPQnHogL1ZpS/sMhq3OyQyq40+K
+GBWaziwPqDZpFvRx6y1KsTlKbdHI3lo9fuh2B+gxKh4ogM/5KBH0FlbbQdUxifk
msp33RH4C3zHt/EhPs01bGCPv2Iam40Q5X5exPMRNUG7OefEbahX5lnDUcBmeQpM
BniOBwauG8sjQIKX0aU7e9ucfCLU6GqWIxylqJD+abDl0T2Bu5S5GLg3dWJfHCe1
9ixWRbCodV04FZnsgY8jE7M70TjKAk2SIlMDbSdhsSa3sfEI5/hBxQSpiINTb9Vs
YpjAuHLFnwTLx0HJ2L8lTLj6Q8lSH58PAzJml35TzPKOJ37Kwl3Hu4aaMr8=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,17 @@
import io
import os
import net.mbedtls
fn main() {
mut client := mbedtls.new_ssl_conn(mbedtls.SSLConnectConfig{
verify: os.resource_abs_path('cert/ca.crt')
cert: os.resource_abs_path('cert/client.crt')
cert_key: os.resource_abs_path('cert/client.key')
validate: true
})!
client.dial('localhost', 8443)!
client.write_string('GET / HTTP/1.1\r\n\r\n')!
mut reader := io.new_buffered_reader(reader: client)
println(reader.read_line()!)
}

View File

@ -0,0 +1,20 @@
import io
import os
import net.mbedtls
fn main() {
mut server := mbedtls.new_ssl_listener('0.0.0.0:8443', mbedtls.SSLConnectConfig{
verify: os.resource_abs_path('cert/ca.crt')
cert: os.resource_abs_path('cert/server.crt')
cert_key: os.resource_abs_path('cert/server.key')
validate: true // mTLS
})!
mut client := server.accept()!
mut reader := io.new_buffered_reader(reader: client)
mut request := reader.read_line()!
println(request)
client.write_string('HTTP/1.1 200 OK\r\n')!
client.shutdown()!
server.shutdown()!
}

View File

@ -49,7 +49,7 @@ V projects can be created anywhere and don't need to have a certain structure:
```bash
mkdir blog
cd blog
v init
touch blog.v
```
First, let's create a simple hello world website:
@ -203,11 +203,11 @@ since a DB connection doesn't have to be set up for each request.
// blog.v
fn main() {
mut app := App{
db: sqlite.connect(':memory:') or { panic(err) }
db: sqlite.connect(':memory:')!
}
sql app.db {
create table Article
}
}!
first_article := Article{
title: 'Hello, world!'
@ -222,7 +222,7 @@ fn main() {
sql app.db {
insert first_article into Article
insert second_article into Article
}
}!
vweb.run(app, 8080)
}
```
@ -242,7 +242,7 @@ struct Article {
pub fn (app &App) find_all_articles() []Article {
return sql app.db {
select from Article
}
} or { panic(err) }
}
```
@ -289,7 +289,7 @@ For example, if we only wanted to find articles with ids between 100 and 200, we
return sql app.db {
select from Article where id >= 100 && id <= 200
}
} or { panic(err) }
```
Retrieving a single article is very simple:
@ -299,7 +299,7 @@ Retrieving a single article is very simple:
pub fn (app &App) retrieve_article() ?Article {
return sql app.db {
select from Article limit 1
}
} or { panic(err) }[0]
}
```
@ -308,9 +308,8 @@ bad queries will always be handled by the developer:
```v ignore
// article.v
article := app.retrieve_article(10) or {
app.text('Article not found')
return
article := app.retrieve_article() or {
return app.text('Article not found')
}
```
@ -349,7 +348,7 @@ pub fn (mut app App) new_article(title string, text string) vweb.Result {
println(article)
sql app.db {
insert article into Article
}
} or { panic(err) }
return app.redirect('/')
}
```
@ -402,7 +401,7 @@ If one wants to persist data they need to use a file instead of memory SQLite Da
Replace the db setup code with this instead:
```
db: sqlite.connect('blog.db') or { panic(err) }
db: sqlite.connect('blog.db')!
```
As we can see it attempts to open a file in the current directory named `blog.db`.

View File

@ -865,7 +865,7 @@ pub fn (s string) split_nth(delim string, nth int) []string {
i = 1
for ch in s {
if nth > 0 && i >= nth {
res << s[i..]
res << s[i - 1..]
break
}
res << ch.ascii_str()
@ -938,7 +938,7 @@ pub fn (s string) rsplit_nth(delim string, nth int) []string {
0 {
for i >= 0 {
if nth > 0 && res.len == nth - 1 {
res << s[..i]
res << s[..i + 1]
break
}
res << s[i].ascii_str()

View File

@ -183,6 +183,15 @@ fn test_split_nth() {
assert e.split_nth(',,', 3).len == 3
assert e.split_nth(',', -1).len == 12
assert e.split_nth(',', 3).len == 3
f := '1:2:3'
assert f.split_nth(':', 2) == ['1', '2:3']
assert f.rsplit_nth(':', 2) == ['3', '1:2']
g := '123'
assert g.split_nth('', 2) == ['1', '23']
assert g.rsplit_nth('', 2) == ['3', '12']
h := ''
assert h.split_nth('', 2) == []
assert h.rsplit_nth('', 2) == []
}
fn test_rsplit_nth() {

View File

@ -18,9 +18,9 @@ pub mut:
description string
man_description string
version string
pre_execute FnCommandCallback
execute FnCommandCallback
post_execute FnCommandCallback
pre_execute FnCommandCallback = unsafe { nil }
execute FnCommandCallback = unsafe { nil }
post_execute FnCommandCallback = unsafe { nil }
disable_help bool
disable_man bool
disable_version bool

View File

@ -151,17 +151,17 @@ pub fn new() &Digest {
}
// new512_224 returns a new Digest (implementing hash.Hash) computing the SHA-512/224 checksum.
fn new512_224() &Digest {
pub fn new512_224() &Digest {
return new_digest(.sha512_224)
}
// new512_256 returns a new Digest (implementing hash.Hash) computing the SHA-512/256 checksum.
fn new512_256() &Digest {
pub fn new512_256() &Digest {
return new_digest(.sha512_256)
}
// new384 returns a new Digest (implementing hash.Hash) computing the SHA-384 checksum.
fn new384() &Digest {
pub fn new384() &Digest {
return new_digest(.sha384)
}

View File

@ -4,13 +4,22 @@ module datatypes
[heap]
struct BloomFilter[T] {
hash_func fn (T) u32 // hash function, input [T] , output u32
table_size int // every entry is one-bit, packed into `table`
num_functions int // 1~16
// TODO V bug
hash_func fn (T) u32 = unsafe { nil } // hash function, input [T] , output u32
// hash_func fn (T) u32 = empty_cb // hash function, input [T] , output u32
table_size int // every entry is one-bit, packed into `table`
num_functions int // 1~16
mut:
table []u8
}
/*
TODO maybe allow pointing to generic fns?
fn empty_cb[T](x T) u32 {
panic('empty BloomFilter.hash_func callback')
}
*/
const (
// Salt values(random values). These salts are XORed with the output of the hash function to give multiple unique hashes.
salts = [

View File

@ -51,3 +51,14 @@ Read this section to learn how to install and connect to PostgreSQL
[*Windows*](https://www.postgresqltutorial.com/install-postgresql);
[*Linux*](https://www.postgresqltutorial.com/postgresql-getting-started/install-postgresql-linux);
[*macOS*](https://www.postgresqltutorial.com/postgresql-getting-started/install-postgresql-macos).
## Using Parameterized Queries
Parameterized queries (exec_param, etc.) in V require the use of the following syntax: ($n).
The number following the $ specifies which parameter from the argument array to use.
```v ignore
db.exec_param_many('INSERT INTO users (username, password) VALUES ($1, $2)', ['tom', 'securePassword']) or { panic(err) }
db.exec_param('SELECT * FROM users WHERE username = ($1) limit 1', 'tom') or { panic(err) }
```

View File

@ -251,7 +251,7 @@ pub fn (db DB) exec_one(query string) !Row {
return row
}
// exec_param_many executes a query with the provided parameters
// exec_param_many executes a query with the parameters provided as ($1), ($2), ($n)
pub fn (db DB) exec_param_many(query string, params []string) ![]Row {
unsafe {
mut param_vals := []&char{len: params.len}
@ -265,12 +265,12 @@ pub fn (db DB) exec_param_many(query string, params []string) ![]Row {
}
}
// exec_param2 executes a query with 1 parameter, and returns either an error on failure, or the full result set on success
// exec_param2 executes a query with 1 parameter ($1), and returns either an error on failure, or the full result set on success
pub fn (db DB) exec_param(query string, param string) ![]Row {
return db.exec_param_many(query, [param])
}
// exec_param2 executes a query with 2 parameters, and returns either an error on failure, or the full result set on success
// exec_param2 executes a query with 2 parameters ($1) and ($2), and returns either an error on failure, or the full result set on success
pub fn (db DB) exec_param2(query string, param string, param2 string) ![]Row {
return db.exec_param_many(query, [param, param2])
}

View File

@ -19,8 +19,8 @@ mut:
struct EventHandler[T] {
name T
handler EventHandlerFn
receiver voidptr = unsafe { nil }
handler EventHandlerFn = unsafe { nil }
receiver voidptr = unsafe { nil }
once bool
}

View File

@ -6,15 +6,15 @@ pub struct C.FONSparams {
flags char
userPtr voidptr
// int (*renderCreate)(void* uptr, int width, int height)
renderCreate fn (uptr voidptr, width int, height int) int
renderCreate fn (uptr voidptr, width int, height int) int = unsafe { nil }
// int (*renderResize)(void* uptr, int width, int height)
renderResize fn (uptr voidptr, width int, height int) int
renderResize fn (uptr voidptr, width int, height int) int = unsafe { nil }
// void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data)
renderUpdate fn (uptr voidptr, rect &int, data &u8)
renderUpdate fn (uptr voidptr, rect &int, data &u8) = unsafe { nil }
// void (*renderDraw)(void* uptr, const float* verts, const float* tcoords, const unsigned int* colors, int nverts)
renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int)
renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int) = unsafe { nil }
// void (*renderDelete)(void* uptr)
renderDelete fn (uptr voidptr)
renderDelete fn (uptr voidptr) = unsafe { nil }
}
pub struct C.FONSquad {

View File

@ -25,15 +25,25 @@ pub mut:
}
// create_image creates an `Image` from `file`.
pub fn (ctx &Context) create_image(file string) !Image {
// println('\ncreate_image("$file")')
pub fn (mut ctx Context) create_image(file string) !Image {
if !os.exists(file) {
return error('image file "${file}" not found')
$if android {
image_data := os.read_apk_asset(file)!
mut image := ctx.create_image_from_byte_array(image_data)!
image.path = file
return image
} $else {
return error('image file "${file}" not found')
}
}
$if macos {
if ctx.native_rendering {
// return C.darwin_create_image(file)
mut img := C.darwin_create_image(file)
// println('created macos image: $img.path w=$img.width')
// C.printf('p = %p\n', img.data)
img.id = ctx.image_cache.len
@ -43,6 +53,7 @@ pub fn (ctx &Context) create_image(file string) !Image {
return img
}
}
if !gfx.is_valid() {
// Sokol is not initialized yet, add stbi object to a queue/cache
// ctx.image_queue << file

View File

@ -382,7 +382,7 @@ pub fn (u_ Uint256) str() string {
}
// uint256_from_dec_str creates a new `unsigned.Uint256` from the given string if possible
pub fn uint256_from_dec_str(value string) ?Uint256 {
pub fn uint256_from_dec_str(value string) !Uint256 {
mut res := unsigned.uint256_zero
for b_ in value.bytes() {
b := b_ - '0'.bytes()[0]

View File

@ -170,7 +170,12 @@ fn C.mbedtls_pk_parse_keyfile(&C.mbedtls_pk_context, &char, &char, voidptr, void
fn C.mbedtls_net_connect(&C.mbedtls_net_context, &u8, &u8, int) int
fn C.mbedtls_ssl_conf_own_cert(&C.mbedtls_ssl_config, &C.mbedtls_x509_crt, &C.mbedtls_pk_context)
fn C.mbedtls_net_bind(&C.mbedtls_net_context, voidptr, &u8, int) int
fn C.mbedtls_net_accept(&C.mbedtls_net_context, &C.mbedtls_net_context, voidptr, int, voidptr) int
fn C.mbedtls_ssl_session_reset(&C.mbedtls_ssl_context)
fn C.mbedtls_ssl_conf_authmode(&C.mbedtls_ssl_config, int)
fn C.mbedtls_ssl_conf_own_cert(&C.mbedtls_ssl_config, &C.mbedtls_x509_crt, &C.mbedtls_pk_context) int
fn C.mbedtls_ssl_conf_authmode(&C.mbedtls_ssl_config, int)
fn C.mbedtls_ssl_conf_ca_chain(&C.mbedtls_ssl_config, &C.mbedtls_x509_crt, &C.mbedtls_x509_crl)
fn C.mbedtls_ssl_conf_rng(&C.mbedtls_ssl_config, voidptr, &C.mbedtls_ctr_drbg_context)

View File

@ -45,6 +45,172 @@ mut:
owns_socket bool
}
// SSLListener listens on a TCP port and accepts connection secured with TLS
pub struct SSLListener {
saddr string
config SSLConnectConfig
mut:
server_fd C.mbedtls_net_context
ssl C.mbedtls_ssl_context
conf C.mbedtls_ssl_config
certs &SSLCerts = unsafe { nil }
opened bool
// handle int
// duration time.Duration
}
// create a new SSLListener binding to `saddr`
pub fn new_ssl_listener(saddr string, config SSLConnectConfig) !&SSLListener {
mut listener := &SSLListener{
saddr: saddr
config: config
}
listener.init()!
listener.opened = true
return listener
}
// finish the listener and clean up resources
pub fn (mut l SSLListener) shutdown() ! {
$if trace_ssl ? {
eprintln(@METHOD)
}
if unsafe { l.certs != nil } {
C.mbedtls_x509_crt_free(&l.certs.cacert)
C.mbedtls_x509_crt_free(&l.certs.client_cert)
C.mbedtls_pk_free(&l.certs.client_key)
}
C.mbedtls_ssl_free(&l.ssl)
C.mbedtls_ssl_config_free(&l.conf)
if l.opened {
C.mbedtls_net_free(&l.server_fd)
}
}
// internal function to init and bind the listener
fn (mut l SSLListener) init() ! {
$if trace_ssl ? {
eprintln(@METHOD)
}
lhost, lport := net.split_address(l.saddr)!
if l.config.cert == '' || l.config.cert_key == '' {
return error('No certificate or key provided')
}
if l.config.validate && l.config.verify == '' {
return error('No root CA provided')
}
C.mbedtls_net_init(&l.server_fd)
C.mbedtls_ssl_init(&l.ssl)
C.mbedtls_ssl_config_init(&l.conf)
l.certs = &SSLCerts{}
C.mbedtls_x509_crt_init(&l.certs.client_cert)
C.mbedtls_pk_init(&l.certs.client_key)
unsafe {
C.mbedtls_ssl_conf_rng(&l.conf, C.mbedtls_ctr_drbg_random, &mbedtls.ctr_drbg)
}
mut ret := 0
if l.config.in_memory_verification {
if l.config.verify != '' {
ret = C.mbedtls_x509_crt_parse(&l.certs.cacert, l.config.verify.str, l.config.verify.len)
}
if l.config.cert != '' {
ret = C.mbedtls_x509_crt_parse(&l.certs.client_cert, l.config.cert.str, l.config.cert.len)
}
if l.config.cert_key != '' {
unsafe {
ret = C.mbedtls_pk_parse_key(&l.certs.client_key, l.config.cert_key.str,
l.config.cert_key.len, 0, 0, C.mbedtls_ctr_drbg_random, &mbedtls.ctr_drbg)
}
}
} else {
if l.config.verify != '' {
ret = C.mbedtls_x509_crt_parse_file(&l.certs.cacert, &char(l.config.verify.str))
}
ret = C.mbedtls_x509_crt_parse_file(&l.certs.client_cert, &char(l.config.cert.str))
unsafe {
ret = C.mbedtls_pk_parse_keyfile(&l.certs.client_key, &char(l.config.cert_key.str),
0, C.mbedtls_ctr_drbg_random, &mbedtls.ctr_drbg)
}
}
if l.config.validate {
C.mbedtls_ssl_conf_authmode(&l.conf, C.MBEDTLS_SSL_VERIFY_REQUIRED)
}
mut bind_ip := unsafe { nil }
if lhost != '' {
bind_ip = voidptr(lhost.str)
}
bind_port := lport.str()
ret = C.mbedtls_net_bind(&l.server_fd, bind_ip, voidptr(bind_port.str), C.MBEDTLS_NET_PROTO_TCP)
if ret != 0 {
return error_with_code("can't bind to ${l.saddr}", ret)
}
ret = C.mbedtls_ssl_config_defaults(&l.conf, C.MBEDTLS_SSL_IS_SERVER, C.MBEDTLS_SSL_TRANSPORT_STREAM,
C.MBEDTLS_SSL_PRESET_DEFAULT)
if ret != 0 {
return error_with_code("can't to set config defaults", ret)
}
C.mbedtls_ssl_conf_ca_chain(&l.conf, &l.certs.cacert, unsafe { nil })
ret = C.mbedtls_ssl_conf_own_cert(&l.conf, &l.certs.client_cert, &l.certs.client_key)
if ret != 0 {
return error_with_code("can't load certificate", ret)
}
ret = C.mbedtls_ssl_setup(&l.ssl, &l.conf)
if ret != 0 {
return error_with_code("can't setup ssl", ret)
}
}
// accepts a new connection and returns a SSLConn of the connected client
pub fn (mut l SSLListener) accept() !&SSLConn {
mut conn := &SSLConn{
conf: l.conf
config: l.config
opened: true
owns_socket: true
}
// TODO: save the client's IP address somewhere (maybe add a field to SSLConn ?)
mut ret := C.mbedtls_net_accept(&l.server_fd, &conn.server_fd, unsafe { nil }, 0,
unsafe { nil })
if ret != 0 {
return error_with_code("can't accept connection", ret)
}
C.mbedtls_ssl_init(&conn.ssl)
C.mbedtls_ssl_config_init(&conn.conf)
ret = C.mbedtls_ssl_setup(&conn.ssl, &l.conf)
if ret != 0 {
return error_with_code('SSL setup failed', ret)
}
C.mbedtls_ssl_set_bio(&conn.ssl, &conn.server_fd, C.mbedtls_net_send, C.mbedtls_net_recv,
unsafe { nil })
ret = C.mbedtls_ssl_handshake(&conn.ssl)
for ret != 0 {
if ret != C.MBEDTLS_ERR_SSL_WANT_READ && ret != C.MBEDTLS_ERR_SSL_WANT_WRITE {
return error_with_code('SSL handshake failed', ret)
}
ret = C.mbedtls_ssl_handshake(&conn.ssl)
}
return conn
}
[params]
pub struct SSLConnectConfig {
verify string // the path to a rootca.pem file, containing trusted CA certificate(s)

View File

@ -284,20 +284,27 @@ mut:
accept_deadline time.Time
}
pub fn listen_tcp(family AddrFamily, saddr string) !&TcpListener {
s := new_tcp_socket(family) or { return error('${err.msg()}; could not create new socket') }
[params]
pub struct ListenOptions {
pub:
dualstack bool = true
backlog int = 128
}
pub fn listen_tcp(family AddrFamily, saddr string, options ListenOptions) !&TcpListener {
mut s := new_tcp_socket(family) or { return error('${err.msg()}; could not create new socket') }
s.set_dualstack(options.dualstack) or {}
addrs := resolve_addrs(saddr, family, .tcp) or {
return error('${err.msg()}; could not resolve address ${saddr}')
}
// TODO(logic to pick here)
addr := addrs[0]
// cast to the correct type
alen := addr.len()
socket_error_message(C.bind(s.handle, voidptr(&addr), alen), 'binding to ${saddr} failed')!
socket_error_message(C.listen(s.handle, 128), 'listening on ${saddr} failed')!
socket_error_message(C.listen(s.handle, options.backlog), 'listening on ${saddr} with maximum backlog pending queue of ${options.backlog}, failed')!
return &TcpListener{
sock: s
accept_deadline: no_deadline

View File

@ -150,9 +150,7 @@ pub fn (mut ws Client) listen() ! {
ws.debug_log('got message: ${msg.opcode}')
match msg.opcode {
.text_frame {
log_msg = 'read: text'
ws.debug_log(log_msg)
unsafe { log_msg.free() }
ws.debug_log('read: text')
ws.send_message_event(msg)
unsafe { msg.free() }
}
@ -184,9 +182,7 @@ pub fn (mut ws Client) listen() ! {
}
}
.close {
log_msg = 'read: close'
ws.debug_log(log_msg)
unsafe { log_msg.free() }
ws.debug_log('read: close')
defer {
ws.manage_clean_close()
}

View File

@ -13,17 +13,15 @@ pub fn input_password(prompt string) !string {
if termios.tcgetattr(0, mut old_state) != 0 {
return last_error()
}
defer {
termios.tcsetattr(0, C.TCSANOW, mut old_state)
println('')
}
mut new_state := old_state
new_state.c_lflag &= termios.invert(C.ECHO) // Disable echoing of characters
termios.tcsetattr(0, C.TCSANOW, mut new_state)
new_state.disable_echo()
termios.set_state(0, new_state)
password := input_opt(prompt) or { return error('Failed to read password') }
termios.set_state(0, old_state)
println('')
return password
}

View File

@ -106,8 +106,6 @@ fn (mut pv Picoev) del(fd int) int {
}
if pv.update_events(fd, picoev.picoev_del) != 0 {
target.loop_id = -1
target.fd = 0
return -1
}
@ -149,15 +147,20 @@ fn (mut pv Picoev) set_timeout(fd int, secs int) {
// timeout event
[direct_array_access; inline]
fn (mut pv Picoev) handle_timeout() {
mut to_remove := []int{}
for fd, timeout in pv.timeouts {
if timeout <= pv.loop.now {
target := pv.file_descriptors[fd]
assert target.loop_id == pv.loop.id
pv.timeouts.delete(fd)
unsafe { target.cb(fd, picoev.picoev_timeout, &pv) }
to_remove << fd
}
}
for fd in to_remove {
target := pv.file_descriptors[fd]
assert target.loop_id == pv.loop.id
pv.timeouts.delete(fd)
unsafe { target.cb(fd, picoev.picoev_timeout, &pv) }
}
}
// accept_callback accepts a new connection from `listen_fd` and adds it to the loop

View File

@ -248,7 +248,7 @@ mut:
// counters for quantifier check (repetitions)
rep int
// validator function pointer
validator FnValidator
validator FnValidator = unsafe { nil }
// groups variables
group_neg bool // negation flag for the group, 0 => no negation > 0 => negataion
group_rep int // repetition of the group
@ -376,7 +376,7 @@ fn (mut re RE) reset_src() {
******************************************************************************/
struct BslsStruct {
ch rune // meta char
validator FnValidator // validator function pointer
validator FnValidator = unsafe { nil } // validator function pointer
}
const (
@ -463,7 +463,7 @@ mut:
cc_type int // type of cc token
ch0 rune // first char of the interval a-b a in this case
ch1 rune // second char of the interval a-b b in this case
validator FnValidator // validator function pointer
validator FnValidator = unsafe { nil } // validator function pointer
}
enum CharClass_parse_state {

View File

@ -6,10 +6,21 @@ pub const used_import = 1
#flag -I @VEXEROOT/thirdparty/sokol/util
#flag freebsd -I /usr/local/include
#flag darwin -fobjc-arc
#flag linux -lX11 -lGL -lXcursor -lXi -lpthread
#flag freebsd -L/usr/local/lib -lX11 -lGL -lXcursor -lXi
#flag openbsd -L/usr/X11R6/lib -lX11 -lGL -lXcursor -lXi
#flag windows -lgdi32
// Note that -lm is needed *only* for sokol_gl.h's usage of sqrtf(),
// but without -lm, this fails:
// `v -cc gcc ~/.vmodules/sdl/examples/sdl_opengl_and_sokol/`
// With tcc, this succeeds with or without -lm:
// `v ~/.vmodules/sdl/examples/sdl_opengl_and_sokol/`
$if !tinyc {
#flag linux -lm
}
// METAL
$if macos {
$if darwin_sokol_glcore33 ? {
@ -19,10 +30,6 @@ $if macos {
#flag -framework Metal -framework Cocoa -framework MetalKit -framework QuartzCore
}
}
$if linux {
#flag -D SOKOL_GLCORE33
}
$if ios {
#flag -DSOKOL_METAL
#flag -framework Foundation -framework Metal -framework MetalKit -framework UIKit

View File

@ -5,14 +5,14 @@ import sokol.memory
[typedef]
pub struct C.sg_allocator {
pub mut:
alloc memory.FnAllocatorAlloc
free memory.FnAllocatorFree
alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
[typedef]
pub struct C.sg_logger {
pub mut:
log_cb memory.FnLogCb
log_cb memory.FnLogCb = unsafe { nil }
user_data voidptr
}

View File

@ -46,8 +46,8 @@ pub type GLContextDesc = C.sg_gl_context_desc
struct C.sg_metal_context_desc {
device voidptr
renderpass_descriptor_cb fn () voidptr
drawable_cb fn () voidptr
renderpass_descriptor_cb fn () voidptr = unsafe { nil }
drawable_cb fn () voidptr = unsafe { nil }
}
pub type MetalContextDesc = C.sg_metal_context_desc
@ -55,8 +55,8 @@ pub type MetalContextDesc = C.sg_metal_context_desc
struct C.sg_d3d11_context_desc {
device voidptr
device_context voidptr
render_target_view_cb fn () voidptr
depth_stencil_view_cb fn () voidptr
render_target_view_cb fn () voidptr = unsafe { nil }
depth_stencil_view_cb fn () voidptr = unsafe { nil }
}
pub type D3D11ContextDesc = C.sg_d3d11_context_desc

View File

@ -5,14 +5,14 @@ import sokol.memory
[typedef]
pub struct C.sapp_allocator {
pub mut:
alloc memory.FnAllocatorAlloc
free memory.FnAllocatorFree
alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
[typedef]
pub struct C.sapp_logger {
pub mut:
log_cb memory.FnLogCb
log_cb memory.FnLogCb = unsafe { nil }
user_data voidptr
}

View File

@ -37,18 +37,19 @@ pub type IconDesc = C.sapp_icon_desc
[typedef]
pub struct C.sapp_desc {
pub:
init_cb fn () // these are the user-provided callbacks without user data
frame_cb fn ()
cleanup_cb fn ()
event_cb fn (&Event) //&sapp_event)
fail_cb fn (&u8)
// these are the user-provided callbacks without user data
init_cb fn () = unsafe { nil }
frame_cb fn () = unsafe { nil }
cleanup_cb fn () = unsafe { nil }
event_cb fn (&Event) = unsafe { nil } // &sapp_event
fail_cb fn (&u8) = unsafe { nil }
user_data voidptr // these are the user-provided callbacks with user data
init_userdata_cb fn (voidptr)
frame_userdata_cb fn (voidptr)
cleanup_userdata_cb fn (voidptr)
event_userdata_cb fn (&Event, voidptr)
fail_userdata_cb fn (&char, voidptr)
init_userdata_cb fn (voidptr) = unsafe { nil }
frame_userdata_cb fn (voidptr) = unsafe { nil }
cleanup_userdata_cb fn (voidptr) = unsafe { nil }
event_userdata_cb fn (&Event, voidptr) = unsafe { nil }
fail_userdata_cb fn (&char, voidptr) = unsafe { nil }
width int // the preferred width of the window / canvas
height int // the preferred height of the window / canvas

View File

@ -6,8 +6,8 @@ import sokol.memory
[typedef]
pub struct C.sfons_allocator_t {
pub:
alloc memory.FnAllocatorAlloc
free memory.FnAllocatorFree
alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}

View File

@ -5,14 +5,14 @@ import sokol.memory
[typedef]
pub struct C.sgl_allocator_t {
pub mut:
alloc memory.FnAllocatorAlloc
free memory.FnAllocatorFree
alloc memory.FnAllocatorAlloc = unsafe { nil }
free memory.FnAllocatorFree = unsafe { nil }
user_data voidptr
}
[typedef]
pub struct C.sgl_logger_t {
pub mut:
log_cb memory.FnLogCb
log_cb memory.FnLogCb = unsafe { nil }
user_data voidptr
}

View File

@ -26,7 +26,7 @@ mut:
nxt &Subscription = unsafe { nil }
}
enum Direction {
pub enum Direction {
pop
push
}

View File

@ -24,9 +24,15 @@ mut:
pub type ThreadCB = fn (mut p PoolProcessor, idx int, task_id int) voidptr
fn empty_cb(mut p PoolProcessor, idx int, task_id int) voidptr {
unsafe {
return nil
}
}
pub struct PoolProcessorConfig {
maxjobs int
callback ThreadCB
callback ThreadCB = empty_cb
}
// new_pool_processor returns a new PoolProcessor instance.

View File

@ -176,7 +176,7 @@ pub fn (mut sem Semaphore) timed_wait(timeout time.Duration) bool {
C.GetSystemTimeAsFileTime(&ft_start)
time_end := ((u64(ft_start.dwHighDateTime) << 32) | ft_start.dwLowDateTime) +
u64(timeout / (100 * time.nanosecond))
mut t_ms := timeout.sys_milliseconds()
mut t_ms := u32(timeout.sys_milliseconds())
C.AcquireSRWLockExclusive(&sem.mtx)
mut res := 0
c = C.atomic_load_u32(&sem.count)

View File

@ -17,7 +17,8 @@ pub fn get_terminal_size() (int, int) {
}
// clear clears current terminal screen.
pub fn clear() {
pub fn clear() bool {
print('\x1b[2J')
print('\x1b[H')
return true
}

View File

@ -97,7 +97,7 @@ pub fn set_tab_title(title string) bool {
// clear clears current terminal screen.
// Implementation taken from https://docs.microsoft.com/en-us/windows/console/clearing-the-screen#example-2.
pub fn clear() {
pub fn clear() bool {
hconsole := C.GetStdHandle(C.STD_OUTPUT_HANDLE)
mut csbi := C.CONSOLE_SCREEN_BUFFER_INFO{}
mut scrollrect := C.SMALL_RECT{}
@ -106,7 +106,7 @@ pub fn clear() {
// Get the number of character cells in the current buffer.
if !C.GetConsoleScreenBufferInfo(hconsole, &csbi) {
return
return false
}
// Scroll the rectangle of the entire buffer.
scrollrect.Left = 0
@ -130,4 +130,5 @@ pub fn clear() {
csbi.dwCursorPosition.Y = 0
C.SetConsoleCursorPosition(hconsole, csbi.dwCursorPosition)
return true
}

View File

@ -41,7 +41,7 @@ fn C.ioctl(fd int, request u64, arg voidptr) int
// for the underlying C.termios structure
[inline]
pub fn flag(value int) TcFlag {
return int(value)
return TcFlag(value)
}
// invert is a platform dependant way to bitwise NOT (~) TcFlag
@ -86,3 +86,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -1,12 +1,6 @@
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
//
// TODO Mac version needs to be implemented
// Will serve as more advanced input method
// based on the work of https://github.com/AmokHuginnsson/replxx
//
module termios
// not used but needed for function declarations
@ -14,45 +8,68 @@ type TcFlag = int
type Speed = int
type Cc = u8
// flag provides a termios flag of the correct size
// for the underlying C.termios structure
// It is only implemented for Unix like OSes
pub fn flag(value int) TcFlag {
$compile_error('feature not available')
}
// invert is a platform dependant way to bitwise NOT (~) TcFlag
// as its length varies across platforms
// It is only implemented for Unix like OSes
pub fn invert(value TcFlag) TcFlag {
$compile_error('feature not available')
}
// termios definitions
// Termios definitions
// Linux https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/bits/termios.h
// OpenBSD https://github.com/openbsd/src/blob/master/sys/sys/termios.h
// FreeBSD https://web.mit.edu/freebsd/head/sys/sys/_termios.h
// Solaris https://github.com/omniti-labs/illumos-omnios/blob/master/usr/src/uts/common/sys/termios.h
// DragonFly https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/sys/_termios.h
// QNX https://github.com/vocho/openqnx/blob/master/trunk/lib/c/public/termios.h
pub struct Termios {
pub mut:
c_iflag TcFlag
c_oflag TcFlag
c_cflag TcFlag
c_lflag TcFlag
c_line Cc
c_cc [32]Cc
c_ispeed Speed
c_ospeed Speed
}
// flag provides a termios flag of the correct size
// for the underlying C.termios structure
pub fn flag(value int) TcFlag {
return TcFlag(value)
}
// invert is a platform dependant way to bitwise NOT (~) TcFlag
// as its length varies across platforms
// It is only implemented for Unix like OSes
pub fn invert(value TcFlag) TcFlag {
return TcFlag(~int(value))
}
// tcgetattr is an unsafe wrapper around C.termios and keeps its semantic
// It is only implemented for Unix like OSes
pub fn tcgetattr(fd int, mut termios_p Termios) int {
$compile_error('feature not available')
pub fn tcgetattr(fd int, mut t Termios) int {
$compile_warn('termios.tcgetattr is not implemented on the platform')
eprintln('tcgetattr, fd: ${fd}, t: ${t}')
return 0
}
// tcsetattr is an unsafe wrapper around C.termios and keeps its semantic
// It is only implemented for Unix like OSes
pub fn tcsetattr(fd int, optional_actions int, mut termios_p Termios) int {
$compile_error('feature not available')
pub fn tcsetattr(fd int, optional_actions int, mut t Termios) int {
eprintln('tcsetattr, fd: ${fd}, optional_actions: ${optional_actions}, t: ${t}')
return 0
}
// ioctl is an unsafe wrapper around C.ioctl and keeps its semantic
[inline]
// It is only implemented for Unix like OSes
pub fn ioctl(fd int, request u64, arg voidptr) int {
$compile_error('feature not available')
eprintln('ioctl, fd: ${fd}, request: ${request}, arg: ${arg}')
return 0
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
eprintln('set_state, fd: ${fd} | new_state: ${new_state}')
return 0
}
// disable_echo disables echoing characters as they are typed
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(8)
}

View File

@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -41,7 +41,7 @@ fn C.ioctl(fd int, request u64, arg voidptr) int
// for the underlying C.termios structure
[inline]
pub fn flag(value int) TcFlag {
return int(value)
return TcFlag(value)
}
// invert is a platform dependant way to bitwise NOT (~) TcFlag
@ -86,3 +86,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -86,3 +86,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -80,3 +80,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int {
return C.ioctl(fd, request, arg)
}
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
mut x := new_state
return tcsetattr(0, C.TCSANOW, mut x)
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
t.c_lflag &= invert(C.ECHO)
}

View File

@ -1,20 +0,0 @@
module termios
fn test_termios() {
mut original_term := Termios{}
tcgetattr(0, mut original_term)
println(original_term)
mut silent_term := original_term
silent_term.c_lflag &= invert(C.ECHO)
tcsetattr(0, C.TCSANOW, mut silent_term)
mut check_term := Termios{}
tcgetattr(0, mut check_term)
assert check_term.c_lflag == silent_term.c_lflag
tcsetattr(0, C.TCSANOW, mut orginal_term)
tcgetattr(0, mut check_term)
assert check_term.c_lflag == orginal_term.c_lflag
}

View File

@ -0,0 +1,35 @@
module termios
fn test_portable() {
assert 123 == int(flag(123))
o := Termios{
c_lflag: flag(0xFFFF)
} // assume c_lflag exists everywhere
// dump( o.c_lflag )
mut n := o
n.c_lflag &= invert(1)
// dump( n.c_lflag )
assert n.c_lflag != o.c_lflag
n.disable_echo() // just assume it exists, and can be called everywhere
assert true
}
[if !windows]
fn test_termios() {
mut original_term := Termios{}
tcgetattr(0, mut original_term)
println(original_term)
mut silent_term := original_term
silent_term.c_lflag &= invert(C.ECHO)
tcsetattr(0, C.TCSANOW, mut silent_term)
mut check_term := Termios{}
tcgetattr(0, mut check_term)
assert check_term.c_lflag == silent_term.c_lflag
tcsetattr(0, C.TCSANOW, mut original_term)
tcgetattr(0, mut check_term)
assert check_term.c_lflag == original_term.c_lflag
}

View File

@ -27,6 +27,15 @@ pub fn invert(value TcFlag) TcFlag {
}
pub struct Termios {
pub mut:
c_iflag TcFlag
c_oflag TcFlag
c_cflag TcFlag
c_lflag TcFlag
c_line Cc
c_cc [32]Cc
c_ispeed Speed
c_ospeed Speed
}
// tcgetattr is an unsafe wrapper around C.termios and keeps its semantic
@ -47,3 +56,13 @@ pub fn tcsetattr(fd int, optional_actions int, mut termios_p Termios) int {
pub fn ioctl(fd int, request u64, arg voidptr) int {
return -1
}
// set_state applies the flags in the `new_state` to the descriptor `fd`.
pub fn set_state(fd int, new_state Termios) int {
return -1
}
// disable_echo disables echoing characters as they are typed,
// when that Termios state is later set with termios.set_state(fd,t)
pub fn (mut t Termios) disable_echo() {
}

View File

@ -135,3 +135,15 @@ pub fn (t Time) strftime(fmt string) string {
C.strftime(&buf[0], usize(sizeof(buf)), fmt_c, tm)
return unsafe { cstring_to_vstring(&char(&buf[0])) }
}
// some *nix system functions (e.g. `C.poll()`, C.epoll_wait()) accept an `int`
// value as *timeout in milliseconds* with the special value `-1` meaning "infinite"
pub fn (d Duration) sys_milliseconds() int {
if d > 2147483647 * millisecond { // treat 2147483647000001 .. C.INT64_MAX as "infinite"
return -1
} else if d <= 0 {
return 0 // treat negative timeouts as 0 - consistent with Unix behaviour
} else {
return int(d / millisecond)
}
}

View File

@ -88,11 +88,11 @@ fn darwin_utc() Time {
}
// dummy to compile with all compilers
pub fn solaris_now() Time {
fn solaris_now() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn solaris_utc() Time {
fn solaris_utc() Time {
return Time{}
}

View File

@ -6,21 +6,21 @@ fn sys_mono_now_darwin() u64 {
}
// darwin_now - dummy fn to compile on all platforms/compilers
pub fn darwin_now() Time {
fn darwin_now() Time {
return Time{}
}
// solaris_now - dummy fn to compile on all platforms/compilers
pub fn solaris_now() Time {
fn solaris_now() Time {
return Time{}
}
// darwin_utc - dummy fn to compile on all platforms/compilers
pub fn darwin_utc() Time {
fn darwin_utc() Time {
return Time{}
}
// solaris_utc - dummy fn to compile on all platforms/compilers
pub fn solaris_utc() Time {
fn solaris_utc() Time {
return Time{}
}

View File

@ -95,12 +95,12 @@ fn linux_utc() Time {
}
// dummy to compile with all compilers
pub fn win_now() Time {
fn win_now() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn win_utc() Time {
fn win_utc() Time {
return Time{}
}
@ -125,15 +125,6 @@ pub fn (d Duration) timespec() C.timespec {
return ts
}
// zero_timespec returns the calendar time in seconds and nanoseconds of the beginning of the Unix epoch.
pub fn zero_timespec() C.timespec {
ts := C.timespec{
tv_sec: 0
tv_nsec: 0
}
return ts
}
// sleep suspends the execution of the calling thread for a given duration (in nanoseconds).
pub fn sleep(duration Duration) {
mut req := C.timespec{duration / second, duration % second}
@ -147,15 +138,3 @@ pub fn sleep(duration Duration) {
}
}
}
// some *nix system functions (e.g. `C.poll()`, C.epoll_wait()) accept an `int`
// value as *timeout in milliseconds* with the special value `-1` meaning "infinite"
pub fn (d Duration) sys_milliseconds() int {
if d > C.INT32_MAX * millisecond { // treat 2147483647000001 .. C.INT64_MAX as "infinite"
return -1
} else if d <= 0 {
return 0 // treat negative timeouts as 0 - consistent with Unix behaviour
} else {
return int(d / millisecond)
}
}

View File

@ -22,11 +22,11 @@ fn solaris_utc() Time {
}
// dummy to compile with all compilers
pub fn darwin_now() Time {
fn darwin_now() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn darwin_utc() Time {
fn darwin_utc() Time {
return Time{}
}

View File

@ -171,7 +171,7 @@ fn win_utc() Time {
}
// unix_time returns Unix time.
pub fn (st SystemTime) unix_time() i64 {
fn (st SystemTime) unix_time() i64 {
tt := C.tm{
tm_sec: st.second
tm_min: st.minute
@ -184,32 +184,32 @@ pub fn (st SystemTime) unix_time() i64 {
}
// dummy to compile with all compilers
pub fn darwin_now() Time {
fn darwin_now() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn linux_now() Time {
fn linux_now() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn solaris_now() Time {
fn solaris_now() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn darwin_utc() Time {
fn darwin_utc() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn linux_utc() Time {
fn linux_utc() Time {
return Time{}
}
// dummy to compile with all compilers
pub fn solaris_utc() Time {
fn solaris_utc() Time {
return Time{}
}
@ -223,15 +223,3 @@ pub struct C.timeval {
pub fn sleep(duration Duration) {
C.Sleep(int(duration / millisecond))
}
// some Windows system functions (e.g. `C.WaitForSingleObject()`) accept an `u32`
// value as *timeout in milliseconds* with the special value `u32(-1)` meaning "infinite"
pub fn (d Duration) sys_milliseconds() u32 {
if d >= u32(-1) * millisecond { // treat 4294967295000000 .. C.INT64_MAX as "infinite"
return u32(-1)
} else if d <= 0 {
return 0 // treat negative timeouts as 0 - consistent with Unix behaviour
} else {
return u32(d / millisecond)
}
}

View File

@ -15,7 +15,7 @@ pub interface Modifier {
pub type InspectorFn = fn (value &ast.Value, data voidptr) !
struct Inspector {
inspector_callback InspectorFn
inspector_callback InspectorFn = unsafe { nil }
mut:
data voidptr
}

View File

@ -381,6 +381,7 @@ pub:
language Language
is_union bool
attrs []Attr
pre_comments []Comment
end_comments []Comment
embeds []Embed
pub mut:
@ -531,10 +532,11 @@ pub:
method_idx int
rec_mut bool // is receiver mutable
rec_share ShareType
language Language // V, C, JS
file_mode Language // whether *the file*, where a function was a '.c.v', '.js.v' etc.
no_body bool // just a definition `fn C.malloc()`
is_builtin bool // this function is defined in builtin/strconv
language Language // V, C, JS
file_mode Language // whether *the file*, where a function was a '.c.v', '.js.v' etc.
no_body bool // just a definition `fn C.malloc()`
is_builtin bool // this function is defined in builtin/strconv
name_pos token.Pos
body_pos token.Pos // function bodys position
file string
generic_names []string
@ -633,7 +635,8 @@ pub:
type_pos token.Pos
is_hidden bool // interface first arg
pub mut:
typ Type
typ Type
comments []Comment
}
pub fn (p &Param) specifier() string {
@ -1194,6 +1197,7 @@ pub:
val_var string
is_range bool
pos token.Pos
kv_pos token.Pos
comments []Comment
val_is_mut bool // `for mut val in vals {` means that modifying `val` will modify the array
// and the array cannot be indexed inside the loop

View File

@ -59,7 +59,7 @@ pub fn (node &CallExpr) fkey() string {
}
// These methods are used only by vfmt, vdoc, and for debugging.
pub fn (node &AnonFn) stringify_anon_decl(t &Table, cur_mod string, m2a map[string]string) string {
pub fn (t &Table) stringify_anon_decl(node &AnonFn, cur_mod string, m2a map[string]string) string {
mut f := strings.new_builder(30)
f.write_string('fn ')
if node.inherited_vars.len > 0 {
@ -79,11 +79,11 @@ pub fn (node &AnonFn) stringify_anon_decl(t &Table, cur_mod string, m2a map[stri
}
f.write_string('] ')
}
stringify_fn_after_name(node.decl, mut f, t, cur_mod, m2a)
t.stringify_fn_after_name(node.decl, mut f, cur_mod, m2a)
return f.str()
}
pub fn (node &FnDecl) stringify_fn_decl(t &Table, cur_mod string, m2a map[string]string) string {
pub fn (t &Table) stringify_fn_decl(node &FnDecl, cur_mod string, m2a map[string]string) string {
mut f := strings.new_builder(30)
if node.is_pub {
f.write_string('pub ')
@ -120,11 +120,11 @@ pub fn (node &FnDecl) stringify_fn_decl(t &Table, cur_mod string, m2a map[string
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
f.write_string(' ')
}
stringify_fn_after_name(node, mut f, t, cur_mod, m2a)
t.stringify_fn_after_name(node, mut f, cur_mod, m2a)
return f.str()
}
fn stringify_fn_after_name(node &FnDecl, mut f strings.Builder, t &Table, cur_mod string, m2a map[string]string) {
fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_mod string, m2a map[string]string) {
mut add_para_types := true
if node.generic_names.len > 0 {
if node.is_method {
@ -149,27 +149,26 @@ fn stringify_fn_after_name(node &FnDecl, mut f strings.Builder, t &Table, cur_mo
}
}
f.write_string('(')
for i, arg in node.params {
for i, param in node.params {
// skip receiver
// if (node.is_method || node.is_interface) && i == 0 {
if node.is_method && i == 0 {
continue
}
if arg.is_hidden {
if param.is_hidden {
continue
}
is_last_arg := i == node.params.len - 1
is_type_only := arg.name == ''
should_add_type := true // is_last_arg || is_type_only || node.params[i + 1].typ != arg.typ ||
is_last_param := i == node.params.len - 1
is_type_only := param.name == ''
should_add_type := true // is_last_param || is_type_only || node.params[i + 1].typ != param.typ ||
// (node.is_variadic && i == node.params.len - 2)
if arg.is_mut {
f.write_string(arg.typ.share().str() + ' ')
if param.is_mut {
f.write_string(param.typ.share().str() + ' ')
}
f.write_string(arg.name)
arg_sym := t.sym(arg.typ)
if arg_sym.kind == .struct_ && (arg_sym.info as Struct).is_anon {
f.write_string(param.name)
param_sym := t.sym(param.typ)
if param_sym.kind == .struct_ && (param_sym.info as Struct).is_anon {
f.write_string(' struct {')
struct_ := arg_sym.info as Struct
struct_ := param_sym.info as Struct
for field in struct_.fields {
f.write_string(' ${field.name} ${t.type_to_str(field.typ)}')
if field.has_default_expr {
@ -181,9 +180,9 @@ fn stringify_fn_after_name(node &FnDecl, mut f strings.Builder, t &Table, cur_mo
}
f.write_string('}')
} else {
mut s := t.type_to_str(arg.typ.clear_flag(.shared_f))
if arg.is_mut {
if s.starts_with('&') && ((!arg_sym.is_number() && arg_sym.kind != .bool)
mut s := t.type_to_str(param.typ.clear_flag(.shared_f))
if param.is_mut {
if s.starts_with('&') && ((!param_sym.is_number() && param_sym.kind != .bool)
|| node.language != .v) {
s = s[1..]
}
@ -194,13 +193,13 @@ fn stringify_fn_after_name(node &FnDecl, mut f strings.Builder, t &Table, cur_mo
if !is_type_only {
f.write_string(' ')
}
if node.is_variadic && is_last_arg {
if node.is_variadic && is_last_param {
f.write_string('...')
}
f.write_string(s)
}
}
if !is_last_arg {
if !is_last_param {
f.write_string(', ')
}
}
@ -218,7 +217,7 @@ struct StringifyModReplacement {
weight int
}
fn shorten_full_name_based_on_aliases(input string, m2a map[string]string) string {
pub fn shorten_full_name_based_on_aliases(input string, m2a map[string]string) string {
if m2a.len == 0 || -1 == input.index_u8(`.`) {
// a simple typename, like `string` or `[]bool`; no module aliasings apply,
// (or there just are not any mappings)

View File

@ -10,8 +10,12 @@ mut:
pub type InspectorFn = fn (node &ast.Node, data voidptr) bool
fn empty_callback(node &ast.Node, data voidptr) bool {
panic('empty ast.walker')
}
struct Inspector {
inspector_callback InspectorFn
inspector_callback InspectorFn = empty_callback
mut:
data voidptr
}

View File

@ -590,7 +590,7 @@ pub fn (mut b Builder) print_warnings_and_errors() {
for stmt in file.stmts {
if stmt is ast.FnDecl {
if stmt.name == fn_name {
fheader := stmt.stringify_fn_decl(b.table, 'main', map[string]string{})
fheader := b.table.stringify_fn_decl(&stmt, 'main', map[string]string{})
redefines << FunctionRedefinition{
fpath: file.path
fline: stmt.pos.line_nr

View File

@ -777,7 +777,7 @@ fn (mut b Builder) cc_linux_cross() {
verror(res.output)
return
}
println(out_name + ' has been successfully compiled')
println(out_name + ' has been successfully cross compiled for linux.')
}
fn (mut c Builder) cc_windows_cross() {
@ -795,10 +795,9 @@ fn (mut c Builder) cc_windows_cross() {
if !c.pref.out_name.to_lower().ends_with('.exe') {
c.pref.out_name += '.exe'
}
c.pref.out_name = os.quoted_path(c.pref.out_name)
mut args := []string{}
args << '${c.pref.cflags}'
args << '-o ${c.pref.out_name}'
args << '-o ${os.quoted_path(c.pref.out_name)}'
args << '-w -L.'
//
cflags := c.get_os_cflags()
@ -839,21 +838,6 @@ fn (mut c Builder) cc_windows_cross() {
} else {
args << cflags.c_options_after_target()
}
/*
winroot := '${pref.default_module_path}/winroot'
if !os.is_dir(winroot) {
winroot_url := 'https://github.com/vlang/v/releases/download/v0.1.10/winroot.zip'
println('"$winroot" not found.')
println('Download it from $winroot_url and save it in ${pref.default_module_path}')
println('Unzip it afterwards.\n')
println('winroot.zip contains all library and header files needed ' + 'to cross-compile for Windows.')
exit(1)
}
mut obj_name := c.out_name
obj_name = obj_name.replace('.exe', '')
obj_name = obj_name.replace('.o.o', '.o')
include := '-I $winroot/include '
*/
if os.user_os() !in ['macos', 'linux', 'termux'] {
println(os.user_os())
panic('your platform is not supported yet')
@ -883,20 +867,7 @@ fn (mut c Builder) cc_windows_cross() {
}
exit(1)
}
/*
if c.pref.build_mode != .build_module {
link_cmd := 'lld-link $obj_name $winroot/lib/libcmt.lib ' + '$winroot/lib/libucrt.lib $winroot/lib/kernel32.lib $winroot/lib/libvcruntime.lib ' + '$winroot/lib/uuid.lib'
if c.pref.show_cc {
println(link_cmd)
}
if os.system(link_cmd) != 0 {
println('Cross compilation for Windows failed. Make sure you have lld linker installed.')
exit(1)
}
// os.rm(obj_name)
}
*/
println(c.pref.out_name + ' has been successfully compiled')
println(c.pref.out_name + ' has been successfully cross compiled for windows.')
}
fn (mut b Builder) build_thirdparty_obj_files() {

View File

@ -173,7 +173,7 @@ fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool {
return false
}
}
if expected.has_flag(.generic) {
if expected.has_flag(.generic) && !got.has_flag(.generic) {
return false
}
return true

View File

@ -39,46 +39,49 @@ pub const (
pub struct Checker {
pref &pref.Preferences = unsafe { nil } // Preferences shared from V struct
pub mut:
table &ast.Table = unsafe { nil }
file &ast.File = unsafe { nil }
nr_errors int
nr_warnings int
nr_notices int
errors []errors.Error
warnings []errors.Warning
notices []errors.Notice
error_lines []int // to avoid printing multiple errors for the same line
expected_type ast.Type
expected_or_type ast.Type // fn() or { 'this type' } eg. string. expected or block type
expected_expr_type ast.Type // if/match is_expr: expected_type
mod string // current module name
const_var &ast.ConstField = unsafe { nil } // the current constant, when checking const declarations
const_deps []string
const_names []string
global_names []string
locked_names []string // vars that are currently locked
rlocked_names []string // vars that are currently read-locked
in_for_count int // if checker is currently in a for loop
should_abort bool // when too many errors/warnings/notices are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time.
returns bool
scope_returns bool
is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this
is_just_builtin_mod bool // true only inside 'builtin'
is_generated bool // true for `[generated] module xyz` .v files
inside_unsafe bool // true inside `unsafe {}` blocks
inside_const bool // true inside `const ( ... )` blocks
inside_anon_fn bool // true inside `fn() { ... }()`
inside_ref_lit bool // true inside `a := &something`
inside_defer bool // true inside `defer {}` blocks
inside_fn_arg bool // `a`, `b` in `a.f(b)`
inside_ct_attr bool // true inside `[if expr]`
inside_x_is_type bool // true inside the Type expression of `if x is Type {`
inside_comptime_for_field bool
skip_flags bool // should `#flag` and `#include` be skipped
fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc
smartcast_mut_pos token.Pos // match mut foo, if mut foo is Foo
smartcast_cond_pos token.Pos // match cond
ct_cond_stack []ast.Expr
table &ast.Table = unsafe { nil }
file &ast.File = unsafe { nil }
nr_errors int
nr_warnings int
nr_notices int
errors []errors.Error
warnings []errors.Warning
notices []errors.Notice
error_lines []int // to avoid printing multiple errors for the same line
expected_type ast.Type
expected_or_type ast.Type // fn() or { 'this type' } eg. string. expected or block type
expected_expr_type ast.Type // if/match is_expr: expected_type
mod string // current module name
const_var &ast.ConstField = unsafe { nil } // the current constant, when checking const declarations
const_deps []string
const_names []string
global_names []string
locked_names []string // vars that are currently locked
rlocked_names []string // vars that are currently read-locked
in_for_count int // if checker is currently in a for loop
should_abort bool // when too many errors/warnings/notices are accumulated, .should_abort becomes true. It is checked in statement/expression loops, so the checker can return early, instead of wasting time.
returns bool
scope_returns bool
is_builtin_mod bool // true inside the 'builtin', 'os' or 'strconv' modules; TODO: remove the need for special casing this
is_just_builtin_mod bool // true only inside 'builtin'
is_generated bool // true for `[generated] module xyz` .v files
inside_unsafe bool // true inside `unsafe {}` blocks
inside_const bool // true inside `const ( ... )` blocks
inside_anon_fn bool // true inside `fn() { ... }()`
inside_ref_lit bool // true inside `a := &something`
inside_defer bool // true inside `defer {}` blocks
inside_fn_arg bool // `a`, `b` in `a.f(b)`
inside_ct_attr bool // true inside `[if expr]`
inside_x_is_type bool // true inside the Type expression of `if x is Type {`
inside_comptime_for_field bool
inside_generic_struct_init bool
cur_struct_generic_types []ast.Type
cur_struct_concrete_types []ast.Type
skip_flags bool // should `#flag` and `#include` be skipped
fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc
smartcast_mut_pos token.Pos // match mut foo, if mut foo is Foo
smartcast_cond_pos token.Pos // match cond
ct_cond_stack []ast.Expr
mut:
stmt_level int // the nesting level inside each stmts list;
// .stmt_level is used to check for `evaluated but not used` ExprStmts like `1 << 1`
@ -2438,11 +2441,19 @@ fn (mut c Checker) stmts_ending_with_expression(mut stmts []ast.Stmt) {
}
fn (mut c Checker) unwrap_generic(typ ast.Type) ast.Type {
if typ.has_flag(.generic) && c.table.cur_fn != unsafe { nil } {
if t_typ := c.table.resolve_generic_to_concrete(typ, c.table.cur_fn.generic_names,
c.table.cur_concrete_types)
{
return t_typ
if typ.has_flag(.generic) {
if c.inside_generic_struct_init {
generic_names := c.cur_struct_generic_types.map(c.table.sym(it).name)
if t_typ := c.table.resolve_generic_to_concrete(typ, generic_names, c.cur_struct_concrete_types) {
return t_typ
}
}
if c.table.cur_fn != unsafe { nil } {
if t_typ := c.table.resolve_generic_to_concrete(typ, c.table.cur_fn.generic_names,
c.table.cur_concrete_types)
{
return t_typ
}
}
}
return typ
@ -3329,7 +3340,9 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
if func := c.table.find_fn(node.name) {
if func.generic_names.len > 0 {
concrete_types := node.concrete_types.map(c.unwrap_generic(it))
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
if concrete_types.all(!it.has_flag(.generic)) {
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
}
}
}
return info.typ
@ -3493,7 +3506,9 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
concrete_types)
{
fn_type = typ_
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
if concrete_types.all(!it.has_flag(.generic)) {
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
}
}
}
node.name = name

View File

@ -1654,6 +1654,26 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
node.return_type = left_sym.info.return_type
return left_sym.info.return_type
} else if final_left_sym.info is ast.ArrayFixed && method_name == 'wait' {
elem_sym := c.table.sym(final_left_sym.info.elem_type)
if elem_sym.kind == .thread {
if node.args.len != 0 {
c.error('`.wait()` does not have any arguments', node.args[0].pos)
}
thread_ret_type := c.unwrap_generic(elem_sym.thread_info().return_type)
if thread_ret_type.has_flag(.option) {
c.error('`.wait()` cannot be called for an array when thread functions return options. Iterate over the arrays elements instead and handle each returned option with `or`.',
node.pos)
} else if thread_ret_type.has_flag(.result) {
c.error('`.wait()` cannot be called for an array when thread functions return results. Iterate over the arrays elements instead and handle each returned result with `or`.',
node.pos)
}
node.return_type = c.table.find_or_register_array(thread_ret_type)
return node.return_type
} else {
c.error('`${left_sym.name}` has no method `wait()` (only thread handles and arrays of them have)',
node.left.pos())
}
} else if left_sym.kind == .char && left_type.nr_muls() == 0 && method_name == 'str' {
c.error('calling `.str()` on type `char` is not allowed, use its address or cast it to an integer instead',
node.left.pos().extend(node.pos))
@ -2304,7 +2324,7 @@ fn (mut c Checker) check_expected_arg_count(mut node ast.CallExpr, f &ast.Fn) !
has_decompose := node.args.filter(it.expr is ast.ArrayDecompose).len > 0
if has_decompose {
// if call(...args) is present
min_required_params = nr_args
min_required_params = nr_args - 1
}
}
if min_required_params < 0 {

View File

@ -70,6 +70,19 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
}
}
}
// Do not allow uninitialized `fn` fields, or force `?fn`
// (allow them in `C.` structs)
if !c.is_builtin_mod && node.language == .v {
sym := c.table.sym(field.typ)
if sym.kind == .function {
if !field.typ.has_flag(.option) && !field.has_default_expr
&& field.attrs.filter(it.name == 'required').len == 0 {
error_msg := 'uninitialized `fn` struct fields are not allowed, since they can result in segfaults; use `?fn` or initialize the field with `=` (if you absolutely want to have unsafe function pointers, use `= unsafe { nil }`)'
c.note(error_msg, field.pos)
}
}
}
if field.has_default_expr {
c.expected_type = field.typ
field.default_expr_typ = c.expr(mut field.default_expr)
@ -155,6 +168,9 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
true)
}
}
} else if c.table.final_sym(field.typ).kind == .function
&& field.default_expr_typ.is_pointer() {
continue
} else {
c.error('incompatible initializer for field `${field.name}`: ${err.msg()}',
field.default_expr.pos())
@ -315,6 +331,9 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
}
struct_sym := c.table.sym(node.typ)
mut old_inside_generic_struct_init := false
mut old_cur_struct_generic_types := []ast.Type{}
mut old_cur_struct_concrete_types := []ast.Type{}
if struct_sym.info is ast.Struct {
// check if the generic param types have been defined
for ct in struct_sym.info.concrete_types {
@ -352,6 +371,20 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
c.error('a non generic struct `${node.typ_str}` used like a generic struct',
node.name_pos)
}
if struct_sym.info.generic_types.len > 0
&& struct_sym.info.generic_types.len == struct_sym.info.concrete_types.len {
old_inside_generic_struct_init = c.inside_generic_struct_init
old_cur_struct_generic_types = c.cur_struct_generic_types.clone()
old_cur_struct_concrete_types = c.cur_struct_concrete_types.clone()
c.inside_generic_struct_init = true
c.cur_struct_generic_types = struct_sym.info.generic_types.clone()
c.cur_struct_concrete_types = struct_sym.info.concrete_types.clone()
defer {
c.inside_generic_struct_init = old_inside_generic_struct_init
c.cur_struct_generic_types = old_cur_struct_generic_types
c.cur_struct_concrete_types = old_cur_struct_concrete_types
}
}
} else if struct_sym.info is ast.Alias {
parent_sym := c.table.sym(struct_sym.info.parent_type)
// e.g. ´x := MyMapAlias{}´, should be a cast to alias type ´x := MyMapAlias(map[...]...)´
@ -613,10 +646,10 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
// and the second part is all fields embedded in the structure
// If the return value data composition form in `c.table.struct_fields()` is modified,
// need to modify here accordingly.
fields := c.table.struct_fields(type_sym)
mut fields := c.table.struct_fields(type_sym)
mut checked_types := []ast.Type{}
for i, field in fields {
for i, mut field in fields {
if field.name in inited_fields {
continue
}
@ -628,7 +661,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
if field.has_default_expr {
if i < info.fields.len && field.default_expr_typ == 0 {
if field.default_expr is ast.StructInit {
if mut field.default_expr is ast.StructInit {
idx := c.table.find_type_idx(field.default_expr.typ_str)
if idx != 0 {
info.fields[i].default_expr_typ = ast.new_type(idx)
@ -637,6 +670,9 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
if field.typ.is_any_kind_of_pointer() {
info.fields[i].default_expr_typ = field.typ
}
} else if field.default_expr is ast.Ident
&& field.default_expr.info is ast.IdentFn {
c.expr(mut field.default_expr)
} else {
if const_field := c.table.global_scope.find_const('${field.default_expr}') {
info.fields[i].default_expr_typ = const_field.typ

View File

@ -1,5 +1,5 @@
struct St{
attr fn()
struct St {
attr fn () = unsafe { nil }
}
fn (s St) attr() {}

View File

@ -0,0 +1,6 @@
vlib/v/checker/tests/fn_array_decompose_arg_mismatch_err_c.vv:2:6: error: expected 0 arguments, but got 1
1 | fn main() {
2 | foo(...args)
| ~~~~~~~
3 | }
4 |

View File

@ -0,0 +1,6 @@
fn main() {
foo(...args)
}
fn foo() {
}

Some files were not shown because too many files have changed in this diff Show More