1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

Compare commits

..

No commits in common. "428fd7f57f29b4c163d046a8c3c849acfa9f4f6f" and "d53d95991dd0ba0018c4229b2625b06b3b07de81" have entirely different histories.

181 changed files with 1701 additions and 2871 deletions

View File

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

View File

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

View File

@ -1,6 +1,7 @@
name: 🚀 Feature Request
description: Suggest an idea for this project
labels: [Feature Request]
title: (feature request summary)
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: 20
timeout-minutes: 10
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: 20
timeout-minutes: 10
env:
VFLAGS: -cc tcc
DISPLAY: :99

View File

@ -1,19 +0,0 @@
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 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
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
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: 20
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Build V

View File

@ -201,23 +201,34 @@ cd v
make
```
## Editor/IDE Plugins
## Installing editor/IDE plugin
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:
V has plugins for many editors:
- [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', 'freebsd', 'openbsd', 'solaris', 'termux']
os_names = ['linux', 'macos', 'windows']
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 := b.table.stringify_fn_decl(&s, mod_name, map[string]string{})
fn_signature := s.stringify_fn_decl(b.table, mod_name, map[string]string{})
fn_mod := s.modname()
if fn_mod == mod_name {
fline := '${fn_mod}: ${fn_signature}'

View File

@ -10,7 +10,6 @@ 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']
@ -250,27 +249,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 {
'<style>${vd.assets['doc_css']}</style>
${tabs(2)}<style>${vd.assets['normalize_css']}</style>
${tabs(2)}<script>${vd.assets['dark_mode_js']}</script>'
'\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>'
} else {
'<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>'
'\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>'
}).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
&& d.head.name != 'README' {
'<div class="doc-toc"><ul>${symbols_toc_str}</ul></div>'
&& vd.docs.len > 1 && 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
}
@ -408,12 +407,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(2)}<section id="${node_id}" class="doc-node${node_class}">')
dnw.writeln('${tabs[1]}<section id="${node_id}" class="doc-node${node_class}">')
if dn.name.len > 0 {
if dn.kind == .const_group {
dnw.write_string('${tabs(3)}<div class="title"><${head_tag}>${sym_name}${hash_link}</${head_tag}>')
dnw.write_string('${tabs[2]}<div class="title"><${head_tag}>${sym_name}${hash_link}</${head_tag}>')
} else {
dnw.write_string('${tabs(3)}<div class="title"><${head_tag}>${dn.kind} ${sym_name}${hash_link}</${head_tag}>')
dnw.write_string('${tabs[2]}<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

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

View File

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

View File

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

View File

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

View File

@ -52,11 +52,6 @@ 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'))
@ -76,7 +71,7 @@ fn print_compare(expected string, found string) {
println(found)
println('============\n')
println('diff:')
println(diff.color_compare_strings(diff_cmd, rand.ulid(), expected, found))
println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected))
println('============\n')
}

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,204 +1,235 @@
(function () {
const docnav = document.querySelector('.doc-nav');
const active = docnav.querySelector('li.active');
active?.scrollIntoView({ block: 'center', inline: 'nearest' });
setupMobileToggle();
setupDarkMode();
setupScrollSpy();
setupSearch();
setupCollapse();
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();
})();
function setupScrollSpy() {
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;
});
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;
});
}
function setupMobileToggle() {
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');
});
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');
});
}
function setupDarkMode() {
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);
});
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';
}
}
function setupSearch() {
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);
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);
}
function createSearchResult(data) {
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;
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;
}
function setupCollapse() {
const dropdownArrows = document.querySelectorAll('.dropdown-arrow');
dropdownArrows.forEach((arrow) => {
arrow.addEventListener('click', (e) => {
const parent = e.target.parentElement.parentElement.parentElement;
parent.classList.toggle('open');
});
});
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');
});
}
}
function debounce(func, timeout) {
let timer;
return (...args) => {
const next = () => func(...args);
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(next, timeout > 0 ? timeout : 300);
};
var 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 == '/') {
const search = document.getElementById('search');
ev.preventDefault();
search.focus();
}
if (ev.key == '/') {
let 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,72 +1,63 @@
<!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>
<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>
<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>
</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,6 +16,7 @@ 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 {
@ -232,9 +233,6 @@ 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 == 'exit' {
if line.len <= -1 || line == '' || line == 'exit' {
break
}
if exit_pos := line.index('exit') {

View File

@ -180,15 +180,6 @@ 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(), expected, found))
println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected))
println('============\n')
nb_fail++
} else {

View File

@ -1,148 +1,150 @@
# JS DOM Cube
# Serve
## Compiling
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)
Drawing with mouse events using DOM API. Adopted from MDN examples.
# Compiling
```
v -b js_browser examples/js_dom_cube/cube.js.v
```
Then you can open `index.html` in your favorite browser.
## 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
```
cd examples/js_dom_cube/
npm init -y
```
Add a `start` and `build` script to the generated `./package.json` file.
Drawing with mouse events using DOM API. Adopted from MDN examples.
Then you can open `index.html` with your favourite browser.
# Serve examples
### 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"
"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`.
```
here is the pure javascript server code
`path './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}`);
});
```
Now you can build and run the project with the added scripts.
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)
```sh
npm run build
npm run start
```
$ cd examples/js_dom_draw/
$ npm run build
```
### V server
The example below uses `vweb` to serve the project.
```v
```v ignore
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() {
// Build the cube.js javascript file
os.execute_or_panic('v -b js_browser cube.js.v ')
// This build server json files
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,150 +1,140 @@
# JS DOM Draw
Drawing with mouse events using DOM API. Adopted from MDN examples.
Drawing with mouse events using the DOM API. Adopted from MDN examples.
## Compiling
```sh
# Compiling
```
v -b js_browser examples/js_dom_draw/draw.js.v
```
Then you can open `index.html` in your favorite browser.
## 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
```
cd examples/js_dom_draw/
npm init -y
```
Add a `start` and `build` script to the generated `./package.json` file.
Then you can open `index.html` with your favourite browser.
# Serve examples
### 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"
"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`.
```
here is the pure javascript server code
`path './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}`);
});
```
Now you can build and run the project with the added scripts.
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)
```sh
npm run build
npm run start
```
$ cd examples/js_dom_draw/
$ npm run build
```
### V server
The example below uses `vweb` to serve the project.
```v
```v ignore
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() {
// Build the draw.js javascript file
os.execute_or_panic('v -b js_browser draw.js.v ')
// This build server json files
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,57 +1,35 @@
# JS DOM Benchmark Chart
![image](https://user-images.githubusercontent.com/63821277/186010833-2ea36f3a-4738-4025-9b23-ac62afe74b81.png)
## Running the App
# 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`
> **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).
- run v project
`v run examples/js_dom_draw_bechmark_chart/v_vweb_orm `
The steps below assume that your current directory path is the examples project directory.
- running v chart
`cd examples/js_dom_draw_bechmark_chart/chart && v run .`
```
cd examples/js_dom_draw_bechmark_chart
```
Dockerfile
[docker build]=> Docker image
[docker run]=> Docker container
Execute the following commands in separate terminal instances.
`sudo docker build -t <name> .`
Run the Benchmarks Typescript Part
`sudo docker run --name <container name> --interactive --tty --publish 3001:3001 <name>`
```sh
npm i --prefix typescript_vanilla_typeorm
npm run start:dev --prefix typescript_vanilla_typeorm
```
`v run .`
Run the Benchmarks V Part
A message like `[Vweb] Running app on http://localhost:3001/` should appear
```sh
v run v_vweb_orm
```
`exit`
Run the Chart
# To implement new benchmarks in v
```
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.
In `examples/js_dom_draw_bechmark_chart/v_vweb_orm/src/main.v` path
Create a route returning a `Response` struct like:
```v ignore
['/sqlite-memory/:count']
@ -87,17 +65,18 @@ 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 `chart/main.v`, create a service to request the benchmark data and decode the response as
`FrameworkBenchmarkResponse`.
In `examples/chart/services.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}'
@ -107,13 +86,26 @@ fn typescript_sqlite_memory() ?FrameworkBenchmarkResponse {
}
```
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.
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
## Roadmap
# ROADMAP
02/09/2022
- [ ] select bench (easy)
- [ ] vsql (easy)

View File

@ -1,21 +0,0 @@
-----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

@ -1,24 +0,0 @@
-----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

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

View File

@ -1,26 +0,0 @@
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

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

View File

@ -1,17 +0,0 @@
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

@ -1,20 +0,0 @@
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
touch blog.v
v init
```
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:')!
db: sqlite.connect(':memory:') or { panic(err) }
}
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,8 +308,9 @@ bad queries will always be handled by the developer:
```v ignore
// article.v
article := app.retrieve_article() or {
return app.text('Article not found')
article := app.retrieve_article(10) or {
app.text('Article not found')
return
}
```
@ -348,7 +349,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('/')
}
```
@ -401,7 +402,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')!
db: sqlite.connect('blog.db') or { panic(err) }
```
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 - 1..]
res << s[i..]
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 + 1]
res << s[..i]
break
}
res << s[i].ascii_str()

View File

@ -183,15 +183,6 @@ 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 = unsafe { nil }
execute FnCommandCallback = unsafe { nil }
post_execute FnCommandCallback = unsafe { nil }
pre_execute FnCommandCallback
execute FnCommandCallback
post_execute FnCommandCallback
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.
pub fn new512_224() &Digest {
fn new512_224() &Digest {
return new_digest(.sha512_224)
}
// new512_256 returns a new Digest (implementing hash.Hash) computing the SHA-512/256 checksum.
pub fn new512_256() &Digest {
fn new512_256() &Digest {
return new_digest(.sha512_256)
}
// new384 returns a new Digest (implementing hash.Hash) computing the SHA-384 checksum.
pub fn new384() &Digest {
fn new384() &Digest {
return new_digest(.sha384)
}

View File

@ -4,22 +4,13 @@ module datatypes
[heap]
struct BloomFilter[T] {
// 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
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
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,14 +51,3 @@ 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 parameters provided as ($1), ($2), ($n)
// exec_param_many executes a query with the provided parameters
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 ($1), and returns either an error on failure, or the full result set on success
// exec_param2 executes a query with 1 parameter, 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 ($1) and ($2), and returns either an error on failure, or the full result set on success
// exec_param2 executes a query with 2 parameters, 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 = unsafe { nil }
receiver voidptr = unsafe { nil }
handler EventHandlerFn
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 = unsafe { nil }
renderCreate fn (uptr voidptr, width int, height int) int
// int (*renderResize)(void* uptr, int width, int height)
renderResize fn (uptr voidptr, width int, height int) int = unsafe { nil }
renderResize fn (uptr voidptr, width int, height int) int
// void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data)
renderUpdate fn (uptr voidptr, rect &int, data &u8) = unsafe { nil }
renderUpdate fn (uptr voidptr, rect &int, data &u8)
// 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) = unsafe { nil }
renderDraw fn (uptr voidptr, verts &f32, tcoords &f32, colors &u32, nverts int)
// void (*renderDelete)(void* uptr)
renderDelete fn (uptr voidptr) = unsafe { nil }
renderDelete fn (uptr voidptr)
}
pub struct C.FONSquad {

View File

@ -25,25 +25,15 @@ pub mut:
}
// create_image creates an `Image` from `file`.
pub fn (mut ctx Context) create_image(file string) !Image {
pub fn (ctx &Context) create_image(file string) !Image {
// println('\ncreate_image("$file")')
if !os.exists(file) {
$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')
}
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
@ -53,7 +43,6 @@ pub fn (mut 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,12 +170,7 @@ 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_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_own_cert(&C.mbedtls_ssl_config, &C.mbedtls_x509_crt, &C.mbedtls_pk_context)
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,172 +45,6 @@ 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,27 +284,20 @@ mut:
accept_deadline time.Time
}
[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 {}
pub fn listen_tcp(family AddrFamily, saddr string) !&TcpListener {
s := new_tcp_socket(family) or { return error('${err.msg()}; could not create new socket') }
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, options.backlog), 'listening on ${saddr} with maximum backlog pending queue of ${options.backlog}, failed')!
socket_error_message(C.listen(s.handle, 128), 'listening on ${saddr} failed')!
return &TcpListener{
sock: s
accept_deadline: no_deadline

View File

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

View File

@ -13,15 +13,17 @@ 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.disable_echo()
termios.set_state(0, new_state)
new_state.c_lflag &= termios.invert(C.ECHO) // Disable echoing of characters
termios.tcsetattr(0, C.TCSANOW, mut 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,6 +106,8 @@ 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
}
@ -147,19 +149,14 @@ 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 {
to_remove << fd
}
}
target := pv.file_descriptors[fd]
assert target.loop_id == pv.loop.id
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) }
pv.timeouts.delete(fd)
unsafe { target.cb(fd, picoev.picoev_timeout, &pv) }
}
}
}

View File

@ -248,7 +248,7 @@ mut:
// counters for quantifier check (repetitions)
rep int
// validator function pointer
validator FnValidator = unsafe { nil }
validator FnValidator
// 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 = unsafe { nil } // validator function pointer
validator FnValidator // 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 = unsafe { nil } // validator function pointer
validator FnValidator // validator function pointer
}
enum CharClass_parse_state {

View File

@ -6,21 +6,10 @@ 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 ? {
@ -30,6 +19,10 @@ $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 = unsafe { nil }
free memory.FnAllocatorFree = unsafe { nil }
alloc memory.FnAllocatorAlloc
free memory.FnAllocatorFree
user_data voidptr
}
[typedef]
pub struct C.sg_logger {
pub mut:
log_cb memory.FnLogCb = unsafe { nil }
log_cb memory.FnLogCb
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 = unsafe { nil }
drawable_cb fn () voidptr = unsafe { nil }
renderpass_descriptor_cb fn () voidptr
drawable_cb fn () voidptr
}
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 = unsafe { nil }
depth_stencil_view_cb fn () voidptr = unsafe { nil }
render_target_view_cb fn () voidptr
depth_stencil_view_cb fn () voidptr
}
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 = unsafe { nil }
free memory.FnAllocatorFree = unsafe { nil }
alloc memory.FnAllocatorAlloc
free memory.FnAllocatorFree
user_data voidptr
}
[typedef]
pub struct C.sapp_logger {
pub mut:
log_cb memory.FnLogCb = unsafe { nil }
log_cb memory.FnLogCb
user_data voidptr
}

View File

@ -37,19 +37,18 @@ pub type IconDesc = C.sapp_icon_desc
[typedef]
pub struct C.sapp_desc {
pub:
// 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 }
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)
user_data voidptr // these are the user-provided callbacks with user data
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 }
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)
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 = unsafe { nil }
free memory.FnAllocatorFree = unsafe { nil }
alloc memory.FnAllocatorAlloc
free memory.FnAllocatorFree
user_data voidptr
}

View File

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

View File

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

View File

@ -24,15 +24,9 @@ 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 = empty_cb
callback ThreadCB
}
// 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 := u32(timeout.sys_milliseconds())
mut t_ms := timeout.sys_milliseconds()
C.AcquireSRWLockExclusive(&sem.mtx)
mut res := 0
c = C.atomic_load_u32(&sem.count)

View File

@ -17,8 +17,7 @@ pub fn get_terminal_size() (int, int) {
}
// clear clears current terminal screen.
pub fn clear() bool {
pub fn clear() {
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() bool {
pub fn clear() {
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() bool {
// Get the number of character cells in the current buffer.
if !C.GetConsoleScreenBufferInfo(hconsole, &csbi) {
return false
return
}
// Scroll the rectangle of the entire buffer.
scrollrect.Left = 0
@ -130,5 +130,4 @@ pub fn clear() bool {
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 TcFlag(value)
return int(value)
}
// invert is a platform dependant way to bitwise NOT (~) TcFlag
@ -86,15 +86,3 @@ 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,15 +84,3 @@ 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,6 +1,12 @@
// 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
@ -8,68 +14,45 @@ type TcFlag = int
type Speed = int
type Cc = u8
// 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
// It is only implemented for Unix like OSes
pub fn flag(value int) TcFlag {
return TcFlag(value)
$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 {
return TcFlag(~int(value))
$compile_error('feature not available')
}
// 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 {
}
// 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 t Termios) int {
$compile_warn('termios.tcgetattr is not implemented on the platform')
eprintln('tcgetattr, fd: ${fd}, t: ${t}')
return 0
pub fn tcgetattr(fd int, mut termios_p Termios) int {
$compile_error('feature not available')
}
// 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 t Termios) int {
eprintln('tcsetattr, fd: ${fd}, optional_actions: ${optional_actions}, t: ${t}')
return 0
pub fn tcsetattr(fd int, optional_actions int, mut termios_p Termios) int {
$compile_error('feature not available')
}
// ioctl is an unsafe wrapper around C.ioctl and keeps its semantic
// It is only implemented for Unix like OSes
[inline]
pub fn ioctl(fd int, request u64, arg voidptr) int {
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)
$compile_error('feature not available')
}

View File

@ -84,15 +84,3 @@ 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,15 +84,3 @@ 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 TcFlag(value)
return int(value)
}
// invert is a platform dependant way to bitwise NOT (~) TcFlag
@ -86,15 +86,3 @@ 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,15 +84,3 @@ 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,15 +86,3 @@ 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,15 +80,3 @@ 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

@ -0,0 +1,20 @@
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

@ -1,35 +0,0 @@
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,15 +27,6 @@ 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
@ -56,13 +47,3 @@ 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,15 +135,3 @@ 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
fn solaris_now() Time {
pub fn solaris_now() Time {
return Time{}
}
// dummy to compile with all compilers
fn solaris_utc() Time {
pub 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
fn darwin_now() Time {
pub fn darwin_now() Time {
return Time{}
}
// solaris_now - dummy fn to compile on all platforms/compilers
fn solaris_now() Time {
pub fn solaris_now() Time {
return Time{}
}
// darwin_utc - dummy fn to compile on all platforms/compilers
fn darwin_utc() Time {
pub fn darwin_utc() Time {
return Time{}
}
// solaris_utc - dummy fn to compile on all platforms/compilers
fn solaris_utc() Time {
pub fn solaris_utc() Time {
return Time{}
}

View File

@ -95,12 +95,12 @@ fn linux_utc() Time {
}
// dummy to compile with all compilers
fn win_now() Time {
pub fn win_now() Time {
return Time{}
}
// dummy to compile with all compilers
fn win_utc() Time {
pub fn win_utc() Time {
return Time{}
}
@ -125,6 +125,15 @@ 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}
@ -138,3 +147,15 @@ 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
fn darwin_now() Time {
pub fn darwin_now() Time {
return Time{}
}
// dummy to compile with all compilers
fn darwin_utc() Time {
pub fn darwin_utc() Time {
return Time{}
}

View File

@ -171,7 +171,7 @@ fn win_utc() Time {
}
// unix_time returns Unix time.
fn (st SystemTime) unix_time() i64 {
pub fn (st SystemTime) unix_time() i64 {
tt := C.tm{
tm_sec: st.second
tm_min: st.minute
@ -184,32 +184,32 @@ fn (st SystemTime) unix_time() i64 {
}
// dummy to compile with all compilers
fn darwin_now() Time {
pub fn darwin_now() Time {
return Time{}
}
// dummy to compile with all compilers
fn linux_now() Time {
pub fn linux_now() Time {
return Time{}
}
// dummy to compile with all compilers
fn solaris_now() Time {
pub fn solaris_now() Time {
return Time{}
}
// dummy to compile with all compilers
fn darwin_utc() Time {
pub fn darwin_utc() Time {
return Time{}
}
// dummy to compile with all compilers
fn linux_utc() Time {
pub fn linux_utc() Time {
return Time{}
}
// dummy to compile with all compilers
fn solaris_utc() Time {
pub fn solaris_utc() Time {
return Time{}
}
@ -223,3 +223,15 @@ 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 = unsafe { nil }
inspector_callback InspectorFn
mut:
data voidptr
}

View File

@ -381,7 +381,6 @@ pub:
language Language
is_union bool
attrs []Attr
pre_comments []Comment
end_comments []Comment
embeds []Embed
pub mut:
@ -532,11 +531,10 @@ 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
name_pos token.Pos
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
body_pos token.Pos // function bodys position
file string
generic_names []string
@ -635,8 +633,7 @@ pub:
type_pos token.Pos
is_hidden bool // interface first arg
pub mut:
typ Type
comments []Comment
typ Type
}
pub fn (p &Param) specifier() string {
@ -1197,7 +1194,6 @@ 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 (t &Table) stringify_anon_decl(node &AnonFn, cur_mod string, m2a map[string]string) string {
pub fn (node &AnonFn) stringify_anon_decl(t &Table, 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 (t &Table) stringify_anon_decl(node &AnonFn, cur_mod string, m2a map[stri
}
f.write_string('] ')
}
t.stringify_fn_after_name(node.decl, mut f, cur_mod, m2a)
stringify_fn_after_name(node.decl, mut f, t, cur_mod, m2a)
return f.str()
}
pub fn (t &Table) stringify_fn_decl(node &FnDecl, cur_mod string, m2a map[string]string) string {
pub fn (node &FnDecl) stringify_fn_decl(t &Table, 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 (t &Table) stringify_fn_decl(node &FnDecl, cur_mod string, m2a map[string
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
f.write_string(' ')
}
t.stringify_fn_after_name(node, mut f, cur_mod, m2a)
stringify_fn_after_name(node, mut f, t, cur_mod, m2a)
return f.str()
}
fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_mod string, m2a map[string]string) {
fn stringify_fn_after_name(node &FnDecl, mut f strings.Builder, t &Table, cur_mod string, m2a map[string]string) {
mut add_para_types := true
if node.generic_names.len > 0 {
if node.is_method {
@ -149,26 +149,27 @@ fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_m
}
}
f.write_string('(')
for i, param in node.params {
for i, arg in node.params {
// skip receiver
// if (node.is_method || node.is_interface) && i == 0 {
if node.is_method && i == 0 {
continue
}
if param.is_hidden {
if arg.is_hidden {
continue
}
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 ||
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 ||
// (node.is_variadic && i == node.params.len - 2)
if param.is_mut {
f.write_string(param.typ.share().str() + ' ')
if arg.is_mut {
f.write_string(arg.typ.share().str() + ' ')
}
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(arg.name)
arg_sym := t.sym(arg.typ)
if arg_sym.kind == .struct_ && (arg_sym.info as Struct).is_anon {
f.write_string(' struct {')
struct_ := param_sym.info as Struct
struct_ := arg_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 {
@ -180,9 +181,9 @@ fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_m
}
f.write_string('}')
} else {
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)
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)
|| node.language != .v) {
s = s[1..]
}
@ -193,13 +194,13 @@ fn (t &Table) stringify_fn_after_name(node &FnDecl, mut f strings.Builder, cur_m
if !is_type_only {
f.write_string(' ')
}
if node.is_variadic && is_last_param {
if node.is_variadic && is_last_arg {
f.write_string('...')
}
f.write_string(s)
}
}
if !is_last_param {
if !is_last_arg {
f.write_string(', ')
}
}
@ -217,7 +218,7 @@ struct StringifyModReplacement {
weight int
}
pub fn shorten_full_name_based_on_aliases(input string, m2a map[string]string) string {
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,12 +10,8 @@ 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 = empty_callback
inspector_callback InspectorFn
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 := b.table.stringify_fn_decl(&stmt, 'main', map[string]string{})
fheader := stmt.stringify_fn_decl(b.table, '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 cross compiled for linux.')
println(out_name + ' has been successfully compiled')
}
fn (mut c Builder) cc_windows_cross() {
@ -795,9 +795,10 @@ 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 ${os.quoted_path(c.pref.out_name)}'
args << '-o ${c.pref.out_name}'
args << '-w -L.'
//
cflags := c.get_os_cflags()
@ -838,6 +839,21 @@ 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')
@ -867,7 +883,20 @@ fn (mut c Builder) cc_windows_cross() {
}
exit(1)
}
println(c.pref.out_name + ' has been successfully cross compiled for windows.')
/*
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')
}
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) && !got.has_flag(.generic) {
if expected.has_flag(.generic) {
return false
}
return true

View File

@ -39,49 +39,46 @@ 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
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
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
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`
@ -2441,19 +2438,11 @@ 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) {
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
}
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
}
}
return typ
@ -3340,9 +3329,7 @@ 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))
if concrete_types.all(!it.has_flag(.generic)) {
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
}
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
}
}
return info.typ
@ -3506,9 +3493,7 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
concrete_types)
{
fn_type = typ_
if concrete_types.all(!it.has_flag(.generic)) {
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
}
c.table.register_fn_concrete_types(func.fkey(), concrete_types)
}
}
node.name = name

View File

@ -1654,26 +1654,6 @@ 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))
@ -2324,7 +2304,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 - 1
min_required_params = nr_args
}
}
if min_required_params < 0 {

View File

@ -70,19 +70,6 @@ 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)
@ -168,9 +155,6 @@ 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())
@ -331,9 +315,6 @@ 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 {
@ -371,20 +352,6 @@ 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[...]...)´
@ -646,10 +613,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.
mut fields := c.table.struct_fields(type_sym)
fields := c.table.struct_fields(type_sym)
mut checked_types := []ast.Type{}
for i, mut field in fields {
for i, field in fields {
if field.name in inited_fields {
continue
}
@ -661,7 +628,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 mut field.default_expr is ast.StructInit {
if 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)
@ -670,9 +637,6 @@ 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 () = unsafe { nil }
struct St{
attr fn()
}
fn (s St) attr() {}

View File

@ -1,6 +0,0 @@
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

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

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