mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: treat the main module like any other v module
This commit is contained in:
parent
81e4d3fd09
commit
78e1127d99
2
.github/workflows/alpine.build.sh
vendored
2
.github/workflows/alpine.build.sh
vendored
@ -8,7 +8,7 @@ uname -a
|
||||
|
||||
make -j4
|
||||
|
||||
./v -version
|
||||
./v version
|
||||
|
||||
du -s .
|
||||
|
||||
|
7
.github/workflows/alpine.test.sh
vendored
7
.github/workflows/alpine.test.sh
vendored
@ -10,7 +10,12 @@ du -s .
|
||||
|
||||
ls -lat
|
||||
|
||||
./v test-compiler
|
||||
##./v test-compiler
|
||||
|
||||
## try running the known failing tests first to get faster feedback
|
||||
./v test vlib/builtin/string_test.v vlib/strings/builder_test.v
|
||||
|
||||
./v test-fixed
|
||||
|
||||
./v build-vbinaries
|
||||
|
||||
|
32
.github/workflows/ci.yml
vendored
32
.github/workflows/ci.yml
vendored
@ -55,15 +55,15 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# - name: Build V
|
||||
# uses: spytheman/docker_alpine_v@v7.0
|
||||
# with:
|
||||
# entrypoint: .github/workflows/alpine.build.sh
|
||||
|
||||
# - name: Test V
|
||||
# uses: spytheman/docker_alpine_v@v7.0
|
||||
# with:
|
||||
# entrypoint: .github/workflows/alpine.test.sh
|
||||
- name: Build V
|
||||
uses: spytheman/docker_alpine_v@v7.0
|
||||
with:
|
||||
entrypoint: .github/workflows/alpine.build.sh
|
||||
|
||||
- name: Test V
|
||||
uses: spytheman/docker_alpine_v@v7.0
|
||||
with:
|
||||
entrypoint: .github/workflows/alpine.test.sh
|
||||
|
||||
macos:
|
||||
runs-on: ${{ matrix.os }}
|
||||
@ -176,8 +176,6 @@ jobs:
|
||||
../../vprod -backend x64 -o 1m 1m.v
|
||||
echo "Running it..."
|
||||
ls
|
||||
- name: V self compilation with -autofree
|
||||
run: ./v -o v2 -autofree cmd/v && ./v2 -o v3 -autofree cmd/v && ./v3 -o v4 -autofree cmd/v
|
||||
# - name: SDL examples
|
||||
# run: git clone --depth 1 https://github.com/vlang/sdl && cd sdl
|
||||
|
||||
@ -188,6 +186,18 @@ jobs:
|
||||
# with:
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
ubuntu-autofree-selfcompile:
|
||||
runs-on: ubuntu-18.04
|
||||
env:
|
||||
VFLAGS: -cc gcc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make -j4
|
||||
- name: V self compilation with -autofree
|
||||
run: ./v -o v2 -autofree cmd/v && ./v2 -o v3 -autofree cmd/v && ./v3 -o v4 -autofree cmd/v
|
||||
|
||||
ubuntu-musl:
|
||||
runs-on: ubuntu-18.04
|
||||
env:
|
||||
|
@ -3,3 +3,7 @@ module main
|
||||
// This prelude is loaded in every v program compiled with -live,
|
||||
// in both the main executable, and in the shared library.
|
||||
import live
|
||||
|
||||
const (
|
||||
no_warning_live_is_used = live.is_used
|
||||
)
|
||||
|
@ -3,3 +3,7 @@ module main
|
||||
// This prelude is loaded in every v program compiled with -live,
|
||||
// but only for the main executable.
|
||||
import live.executable
|
||||
|
||||
const (
|
||||
no_warning_live_executable_is_used = executable.is_used
|
||||
)
|
||||
|
@ -3,3 +3,7 @@ module main
|
||||
// This prelude is loaded in every v program compiled with -live,
|
||||
// but only for the shared library.
|
||||
import live.shared
|
||||
|
||||
const (
|
||||
no_warning_live_shared_is_used = shared.is_used
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
module main
|
||||
|
||||
import os
|
||||
import term
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// / This file will get compiled as part of the main program,
|
||||
// / for a _test.v file.
|
||||
@ -11,7 +12,7 @@ import os
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// TODO copy pasta builtin.v fn ___print_assert_failure
|
||||
fn cb_assertion_failed(i &VAssertMetaInfo) {
|
||||
// color_on := term.can_show_color_on_stderr()
|
||||
use_color := term.can_show_color_on_stderr()
|
||||
use_relative_paths := match os.getenv('VERROR_PATHS') {
|
||||
'absolute' {
|
||||
false
|
||||
@ -20,18 +21,22 @@ fn cb_assertion_failed(i &VAssertMetaInfo) {
|
||||
}
|
||||
}
|
||||
final_filename := if use_relative_paths { i.fpath } else { os.real_path(i.fpath) }
|
||||
final_funcname := i.fn_name.replace('main__', '').replace('__', '.')
|
||||
final_funcname := i.fn_name.replace('main.', '').replace('__', '.')
|
||||
final_src := if use_color { term.bold(i.src) } else { i.src }
|
||||
eprintln('')
|
||||
eprintln('$final_filename:${i.line_nr+1}: failed assert in ${final_funcname}')
|
||||
eprintln('Source : ${i.src}')
|
||||
eprintln('$final_filename:${i.line_nr+1}: failed assert in function ${final_funcname}')
|
||||
eprintln('Source : `${final_src}`')
|
||||
if i.op.len > 0 && i.op != 'call' {
|
||||
eprintln(' left value: ${i.llabel} = ${i.lvalue}')
|
||||
if i.rlabel == i.rvalue {
|
||||
eprintln(' right value: $i.rlabel')
|
||||
}
|
||||
else {
|
||||
eprintln(' right value: ${i.rlabel} = ${i.rvalue}')
|
||||
mut slvalue := '${i.lvalue}'
|
||||
mut srvalue := '${i.rvalue}'
|
||||
lpostfix := if slvalue == i.llabel { '.' } else { '<= `${i.llabel}`' }
|
||||
rpostfix := if srvalue == i.rlabel { '.' } else { '<= `${i.rlabel}`' }
|
||||
if use_color {
|
||||
slvalue = term.bold(term.yellow(slvalue))
|
||||
srvalue = term.bold(term.yellow(srvalue))
|
||||
}
|
||||
eprintln(' left value: ${slvalue} ${lpostfix}')
|
||||
eprintln(' right value: ${srvalue} ${rpostfix}')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ fn start_testing(total_number_of_tests int, vfilename string) BenchedTests {
|
||||
|
||||
// Called before each test_ function, defined in file_test.v
|
||||
fn (mut b BenchedTests) testing_step_start(stepfunc string) {
|
||||
b.step_func_name = stepfunc.replace('main__', '').replace('__', '.')
|
||||
b.step_func_name = stepfunc.replace('main.', '').replace('__', '.')
|
||||
b.oks = C.g_test_oks
|
||||
b.fails = C.g_test_fails
|
||||
b.bench.step()
|
||||
|
@ -15,6 +15,7 @@ const (
|
||||
'vlib/sqlite/sqlite_test.v',
|
||||
'vlib/orm/orm_test.v',
|
||||
'vlib/clipboard/clipboard_test.v',
|
||||
'vlib/v/gen/js/jsgen_test.v',
|
||||
]
|
||||
skip_on_linux = []string{}
|
||||
skip_on_non_linux = [
|
||||
|
@ -67,8 +67,8 @@ pub fn (input BitField) str() string {
|
||||
pub fn new(size int) BitField {
|
||||
output := BitField{
|
||||
size: size
|
||||
//field: *u32(calloc(bitnslots(size) * slot_size / 8))
|
||||
field: []u32{len:bitnslots(size)}
|
||||
//field: *u32(calloc(zbitnslots(size) * slot_size / 8))
|
||||
field: []u32{len:zbitnslots(size)}
|
||||
}
|
||||
return output
|
||||
}
|
||||
@ -105,7 +105,7 @@ pub fn (mut instance BitField) clear_bit(bitnr int) {
|
||||
|
||||
// set_all sets all bits in the array to 1.
|
||||
pub fn (mut instance BitField) set_all() {
|
||||
for i in 0..bitnslots(instance.size) {
|
||||
for i in 0..zbitnslots(instance.size) {
|
||||
instance.field[i] = u32(-1)
|
||||
}
|
||||
instance.clear_tail()
|
||||
@ -113,7 +113,7 @@ pub fn (mut instance BitField) set_all() {
|
||||
|
||||
// clear_all clears (sets to zero) all bits in the array.
|
||||
pub fn (mut instance BitField) clear_all() {
|
||||
for i in 0..bitnslots(instance.size) {
|
||||
for i in 0..zbitnslots(instance.size) {
|
||||
instance.field[i] = u32(0)
|
||||
}
|
||||
}
|
||||
@ -132,7 +132,7 @@ pub fn (mut instance BitField) toggle_bit(bitnr int) {
|
||||
// the tail of the longer one is ignored.
|
||||
pub fn bf_and(input1 BitField, input2 BitField) BitField {
|
||||
size := min(input1.size, input2.size)
|
||||
bitnslots := bitnslots(size)
|
||||
bitnslots := zbitnslots(size)
|
||||
mut output := new(size)
|
||||
for i in 0..bitnslots {
|
||||
output.field[i] = input1.field[i] & input2.field[i]
|
||||
@ -144,7 +144,7 @@ pub fn bf_and(input1 BitField, input2 BitField) BitField {
|
||||
// bf_not toggles all bits in a bit array and returns the result as a new array.
|
||||
pub fn bf_not(input BitField) BitField {
|
||||
size := input.size
|
||||
bitnslots := bitnslots(size)
|
||||
bitnslots := zbitnslots(size)
|
||||
mut output := new(size)
|
||||
for i in 0..bitnslots {
|
||||
output.field[i] = ~input.field[i]
|
||||
@ -158,7 +158,7 @@ pub fn bf_not(input BitField) BitField {
|
||||
// the tail of the longer one is ignored.
|
||||
pub fn bf_or(input1 BitField, input2 BitField) BitField {
|
||||
size := min(input1.size, input2.size)
|
||||
bitnslots := bitnslots(size)
|
||||
bitnslots := zbitnslots(size)
|
||||
mut output := new(size)
|
||||
for i in 0..bitnslots {
|
||||
output.field[i] = input1.field[i] | input2.field[i]
|
||||
@ -172,7 +172,7 @@ pub fn bf_or(input1 BitField, input2 BitField) BitField {
|
||||
// the tail of the longer one is ignored.
|
||||
pub fn bf_xor(input1 BitField, input2 BitField) BitField {
|
||||
size := min(input1.size, input2.size)
|
||||
bitnslots := bitnslots(size)
|
||||
bitnslots := zbitnslots(size)
|
||||
mut output := new(size)
|
||||
for i in 0..bitnslots {
|
||||
output.field[i] = input1.field[i] ^ input2.field[i]
|
||||
@ -186,7 +186,7 @@ pub fn join(input1 BitField, input2 BitField) BitField {
|
||||
output_size := input1.size + input2.size
|
||||
mut output := new(output_size)
|
||||
// copy the first input to output as is
|
||||
for i in 0..bitnslots(input1.size) {
|
||||
for i in 0..zbitnslots(input1.size) {
|
||||
output.field[i] = input1.field[i]
|
||||
}
|
||||
|
||||
@ -194,7 +194,7 @@ pub fn join(input1 BitField, input2 BitField) BitField {
|
||||
offset_bit := input1.size % slot_size
|
||||
offset_slot := input1.size / slot_size
|
||||
|
||||
for i in 0..bitnslots(input2.size) {
|
||||
for i in 0..zbitnslots(input2.size) {
|
||||
output.field[i + offset_slot] |=
|
||||
u32(input2.field[i] << u32(offset_bit))
|
||||
}
|
||||
@ -213,12 +213,12 @@ pub fn join(input1 BitField, input2 BitField) BitField {
|
||||
* If offset_bit is zero, no additional copies needed.
|
||||
*/
|
||||
if (output_size - 1) % slot_size < (input2.size - 1) % slot_size {
|
||||
for i in 0..bitnslots(input2.size) {
|
||||
for i in 0..zbitnslots(input2.size) {
|
||||
output.field[i + offset_slot + 1] |=
|
||||
u32(input2.field[i] >> u32(slot_size - offset_bit))
|
||||
}
|
||||
} else if (output_size - 1) % slot_size > (input2.size - 1) % slot_size {
|
||||
for i in 0..bitnslots(input2.size) - 1 {
|
||||
for i in 0..zbitnslots(input2.size) - 1 {
|
||||
output.field[i + offset_slot + 1] |=
|
||||
u32(input2.field[i] >> u32(slot_size - offset_bit))
|
||||
}
|
||||
@ -233,7 +233,7 @@ pub fn (instance BitField) get_size() int {
|
||||
|
||||
// clone creates a copy of a bit array.
|
||||
pub fn (instance BitField) clone() BitField {
|
||||
bitnslots := bitnslots(instance.size)
|
||||
bitnslots := zbitnslots(instance.size)
|
||||
mut output := new(instance.size)
|
||||
for i in 0..bitnslots {
|
||||
output.field[i] = instance.field[i]
|
||||
@ -245,7 +245,7 @@ pub fn (instance BitField) clone() BitField {
|
||||
// identical by length and contents and 'false' otherwise.
|
||||
pub fn (instance BitField) cmp(input BitField) bool {
|
||||
if instance.size != input.size {return false}
|
||||
for i in 0..bitnslots(instance.size) {
|
||||
for i in 0..zbitnslots(instance.size) {
|
||||
if instance.field[i] != input.field[i] {return false}
|
||||
}
|
||||
return true
|
||||
@ -254,7 +254,7 @@ pub fn (instance BitField) cmp(input BitField) bool {
|
||||
// pop_count returns the number of set bits (ones) in the array.
|
||||
pub fn (instance BitField) pop_count() int {
|
||||
size := instance.size
|
||||
bitnslots := bitnslots(size)
|
||||
bitnslots := zbitnslots(size)
|
||||
tail := size % slot_size
|
||||
mut count := 0
|
||||
for i in 0..bitnslots - 1 {
|
||||
@ -318,7 +318,7 @@ pub fn (input BitField) slice(_start int, _end int) BitField {
|
||||
end_offset := (end - 1) % slot_size
|
||||
start_slot := start / slot_size
|
||||
end_slot := (end - 1) / slot_size
|
||||
output_slots := bitnslots(end - start)
|
||||
output_slots := zbitnslots(end - start)
|
||||
|
||||
if output_slots > 1 {
|
||||
if start_offset != 0 {
|
||||
@ -371,7 +371,7 @@ pub fn (input BitField) slice(_start int, _end int) BitField {
|
||||
// last, the second with the last but one and so on).
|
||||
pub fn (instance BitField) reverse() BitField {
|
||||
size := instance.size
|
||||
bitnslots := bitnslots(size)
|
||||
bitnslots := zbitnslots(size)
|
||||
mut output := new(size)
|
||||
for i:= 0; i < (bitnslots - 1); i++ {
|
||||
for j in 0..slot_size {
|
||||
@ -391,9 +391,9 @@ pub fn (instance BitField) reverse() BitField {
|
||||
|
||||
// resize changes the size of the bit array to 'new_size'.
|
||||
pub fn (mut instance BitField) resize(new_size int) {
|
||||
new_bitnslots := bitnslots(new_size)
|
||||
new_bitnslots := zbitnslots(new_size)
|
||||
old_size := instance.size
|
||||
old_bitnslots := bitnslots(old_size)
|
||||
old_bitnslots := zbitnslots(old_size)
|
||||
mut field := []u32{len:new_bitnslots}
|
||||
for i := 0; i < old_bitnslots && i < new_bitnslots; i++ {
|
||||
field[i] = instance.field[i]
|
||||
@ -439,7 +439,7 @@ fn (mut instance BitField) clear_tail() {
|
||||
// create a mask for the tail
|
||||
mask := u32((1 << tail) - 1)
|
||||
// clear the extra bits
|
||||
instance.field[bitnslots(instance.size) - 1] = instance.field[bitnslots(instance.size) - 1] & mask
|
||||
instance.field[zbitnslots(instance.size) - 1] = instance.field[zbitnslots(instance.size) - 1] & mask
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,6 +460,6 @@ fn min(input1 int, input2 int) int {
|
||||
}
|
||||
}
|
||||
|
||||
fn bitnslots(length int) int {
|
||||
fn zbitnslots(length int) int {
|
||||
return (length - 1) / slot_size + 1
|
||||
}
|
||||
|
@ -168,22 +168,22 @@ pub fn v_realloc(b byteptr, n int) byteptr {
|
||||
if ptr == 0 {
|
||||
panic('realloc($n) failed')
|
||||
}
|
||||
|
||||
return ptr
|
||||
}
|
||||
|
||||
[unsafe_fn]
|
||||
pub fn v_calloc(n int) byteptr {
|
||||
return C.calloc(n, 1)
|
||||
return C.calloc(1, n)
|
||||
}
|
||||
|
||||
[unsafe_fn]
|
||||
pub fn vcalloc(n int) byteptr {
|
||||
if n < 0 {
|
||||
panic('calloc(<=0)')
|
||||
} else if n == 0 {
|
||||
return byteptr(0)
|
||||
} else {
|
||||
return C.calloc(n, 1)
|
||||
}
|
||||
return C.calloc(1, n)
|
||||
}
|
||||
|
||||
[unsafe_fn]
|
||||
@ -223,7 +223,7 @@ fn __as_cast(obj voidptr, obj_type, expected_type int) voidptr {
|
||||
|
||||
// VAssertMetaInfo is used during assertions. An instance of it
|
||||
// is filled in by compile time generated code, when an assertion fails.
|
||||
struct VAssertMetaInfo {
|
||||
pub struct VAssertMetaInfo {
|
||||
pub:
|
||||
fpath string // the source file path of the assertion
|
||||
line_nr int // the line number of the assertion
|
||||
|
@ -126,9 +126,9 @@ fn test_various_map_value() {
|
||||
m12['test'] = f64(0.0)
|
||||
assert m12['test'] == f64(0.0)
|
||||
|
||||
mut m13 := map[string]rune
|
||||
m13['test'] = rune(0)
|
||||
assert m13['test'] == rune(0)
|
||||
//mut m13 := map[string]rune
|
||||
//m13['test'] = rune(0)
|
||||
//assert m13['test'] == rune(0)
|
||||
|
||||
mut m14 := map[string]voidptr
|
||||
m14['test'] = voidptr(0)
|
||||
|
@ -1369,7 +1369,11 @@ pub fn (s string) fields() []string {
|
||||
}
|
||||
|
||||
pub fn (s string) map(func fn(byte) byte) string {
|
||||
return string(s.bytes().map(func(it)))
|
||||
mut res := malloc(s.len + 1)
|
||||
for i in 0..s.len {
|
||||
res[i] = func(s[i])
|
||||
}
|
||||
return tos(res, s.len)
|
||||
}
|
||||
|
||||
// Allows multi-line strings to be formatted in a way that removes white-space
|
||||
|
@ -762,10 +762,20 @@ fn test_string_map() {
|
||||
$if windows {
|
||||
return // TODO
|
||||
}
|
||||
a := 'Hello'.map(fn (b byte) byte {
|
||||
original := 'Hello'
|
||||
println('original.len = $original.len')
|
||||
a := original.map(fn (b byte) byte {
|
||||
return b + 1
|
||||
})
|
||||
assert a == 'Ifmmp'
|
||||
expected := 'Ifmmp'
|
||||
println('a[0] = ' + a[0].str())
|
||||
println('a[1] = ' + a[1].str())
|
||||
println('a[2] = ' + a[2].str())
|
||||
println('a[3] = ' + a[3].str())
|
||||
println('a[4] = ' + a[4].str())
|
||||
println('a.len = $a.len')
|
||||
assert a.len == expected.len
|
||||
assert a == expected
|
||||
|
||||
assert 'foo'.map(foo) == r'\ee'
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
module live
|
||||
|
||||
pub const (
|
||||
is_used = 1
|
||||
)
|
||||
|
||||
pub type FNLinkLiveSymbols = fn (linkcb voidptr)
|
||||
|
||||
pub type FNLiveReloadCB = fn (info &LiveReloadInfo)
|
||||
|
@ -6,6 +6,10 @@ import dl
|
||||
import strconv
|
||||
import live
|
||||
|
||||
pub const (
|
||||
is_used = 1
|
||||
)
|
||||
|
||||
// The live reloader code is implemented here.
|
||||
|
||||
// NB: new_live_reload_info will be called by generated C code inside main()
|
||||
|
@ -1,3 +1,7 @@
|
||||
module shared
|
||||
|
||||
import live
|
||||
|
||||
pub const (
|
||||
is_used = 1
|
||||
)
|
||||
|
@ -203,10 +203,10 @@ pub fn mean_absdev(arr []f64) f64 {
|
||||
if arr.len == 0 {
|
||||
return f64(0)
|
||||
}
|
||||
mean := mean(arr)
|
||||
amean := mean(arr)
|
||||
mut sum := f64(0)
|
||||
for v in arr {
|
||||
sum += math.abs(v-mean)
|
||||
sum += math.abs(v-amean)
|
||||
}
|
||||
return sum/f64(arr.len)
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
module main
|
||||
|
||||
import net.ftp
|
||||
|
||||
// NB: this function makes network calls to external servers,
|
||||
|
@ -49,21 +49,26 @@ pub fn (mut b Builder) go_back(n int) {
|
||||
b.len -= n
|
||||
}
|
||||
|
||||
fn bytes2string(b []byte) string {
|
||||
mut copy := b.clone()
|
||||
copy << `\0`
|
||||
res := tos(copy.data, copy.len-1)
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (mut b Builder) cut_last(n int) string {
|
||||
buf := b.buf[b.len-n..]
|
||||
s := string(buf.clone())
|
||||
res := bytes2string( b.buf[b.len-n..] )
|
||||
b.buf.trim(b.buf.len-n)
|
||||
b.len -= n
|
||||
return s
|
||||
return res
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn (mut b Builder) cut_to(pos int) string {
|
||||
buf := b.buf[pos..]
|
||||
s := string(buf.clone())
|
||||
res := bytes2string( b.buf[pos..] )
|
||||
b.buf.trim(pos)
|
||||
b.len = pos
|
||||
return s
|
||||
return res
|
||||
}
|
||||
*/
|
||||
|
||||
@ -88,8 +93,7 @@ pub fn (b &Builder) last_n(n int) string {
|
||||
if n > b.len {
|
||||
return ''
|
||||
}
|
||||
buf := b.buf[b.len-n..]
|
||||
return string(buf.clone())
|
||||
return bytes2string( b.buf[b.len-n..] )
|
||||
}
|
||||
|
||||
// buf == 'hello world'
|
||||
@ -98,10 +102,7 @@ pub fn (b &Builder) after(n int) string {
|
||||
if n >= b.len {
|
||||
return ''
|
||||
}
|
||||
buf := b.buf[n..]
|
||||
mut copy := buf.clone()
|
||||
copy << `\0`
|
||||
return string(copy)
|
||||
return bytes2string( b.buf[n..] )
|
||||
}
|
||||
|
||||
// NB: in order to avoid memleaks and additional memory copies, after a call to b.str(),
|
||||
|
@ -6,7 +6,8 @@ fn test_sb() {
|
||||
sb.write('!')
|
||||
sb.write('hello')
|
||||
assert sb.len == 8
|
||||
assert sb.str() == 'hi!hello'
|
||||
sb_end := sb.str()
|
||||
assert sb_end == 'hi!hello'
|
||||
assert sb.len == 0
|
||||
///
|
||||
sb = strings.new_builder(10)
|
||||
@ -19,39 +20,33 @@ fn test_sb() {
|
||||
// TODO msvc bug
|
||||
sb = strings.new_builder(10)
|
||||
sb.write('123456')
|
||||
assert sb.cut_last(2) == '56'
|
||||
assert sb.str() == '1234'
|
||||
last_2 := sb.cut_last(2)
|
||||
assert last_2 == '56'
|
||||
final_sb := sb.str()
|
||||
assert final_sb == '1234'
|
||||
}
|
||||
///
|
||||
/*
|
||||
sb = strings.new_builder(10)
|
||||
sb.write('123456')
|
||||
x := sb.cut_to(2)
|
||||
assert x == '456'
|
||||
assert sb.str() == '123'
|
||||
*/
|
||||
}
|
||||
|
||||
const (
|
||||
n = 100000
|
||||
maxn = 100000
|
||||
)
|
||||
|
||||
fn test_big_sb() {
|
||||
mut sb := strings.new_builder(100)
|
||||
mut sb2 := strings.new_builder(10000)
|
||||
for i in 0..n {
|
||||
for i in 0..maxn {
|
||||
sb.writeln(i.str())
|
||||
sb2.write('+')
|
||||
}
|
||||
s := sb.str()
|
||||
lines := s.split_into_lines()
|
||||
assert lines.len == n
|
||||
assert lines.len == maxn
|
||||
assert lines[0] == '0'
|
||||
assert lines[1] == '1'
|
||||
assert lines[777] == '777'
|
||||
assert lines[98765] == '98765'
|
||||
println(sb2.len)
|
||||
assert sb2.len == n
|
||||
assert sb2.len == maxn
|
||||
|
||||
}
|
||||
|
||||
@ -64,5 +59,6 @@ fn test_byte_write() {
|
||||
count++
|
||||
assert count == sb.len
|
||||
}
|
||||
assert sb.str() == temp_str
|
||||
sb_final := sb.str()
|
||||
assert sb_final == temp_str
|
||||
}
|
||||
|
@ -48,13 +48,13 @@ pub fn (t Time) md() string {
|
||||
// - a date string in "MMM D HH:MM" format (24h) for date of current year
|
||||
// - a date string formatted with format function for other dates
|
||||
pub fn (t Time) clean() string {
|
||||
now := time.now()
|
||||
znow := time.now()
|
||||
// Today
|
||||
if t.month == now.month && t.year == now.year && t.day == now.day {
|
||||
if t.month == znow.month && t.year == znow.year && t.day == znow.day {
|
||||
return t.get_fmt_time_str(.hhmm24)
|
||||
}
|
||||
// This year
|
||||
if t.year == now.year {
|
||||
if t.year == znow.year {
|
||||
return t.get_fmt_str(.space, .hhmm24, .mmmd)
|
||||
}
|
||||
return t.format()
|
||||
@ -65,13 +65,13 @@ pub fn (t Time) clean() string {
|
||||
// - a date string in "MMM D HH:MM" format (12h) for date of current year
|
||||
// - a date string formatted with format function for other dates
|
||||
pub fn (t Time) clean12() string {
|
||||
now := time.now()
|
||||
znow := time.now()
|
||||
// Today
|
||||
if t.month == now.month && t.year == now.year && t.day == now.day {
|
||||
if t.month == znow.month && t.year == znow.year && t.day == znow.day {
|
||||
return t.get_fmt_time_str(.hhmm12)
|
||||
}
|
||||
// This year
|
||||
if t.year == now.year {
|
||||
if t.year == znow.year {
|
||||
return t.get_fmt_str(.space, .hhmm12, .mmmd)
|
||||
}
|
||||
return t.format()
|
||||
|
@ -189,8 +189,8 @@ fn since(t Time) int {
|
||||
// relative returns a string representation of difference between time
|
||||
// and current time.
|
||||
pub fn (t Time) relative() string {
|
||||
now := time.now()
|
||||
secs := now.unix - t.unix
|
||||
znow := time.now()
|
||||
secs := znow.unix - t.unix
|
||||
if secs <= 30 {
|
||||
// right now or in the future
|
||||
// TODO handle time in the future
|
||||
@ -227,8 +227,8 @@ pub fn (t Time) relative() string {
|
||||
}
|
||||
|
||||
pub fn (t Time) relative_short() string {
|
||||
now := time.now()
|
||||
secs := now.unix - t.unix
|
||||
znow := time.now()
|
||||
secs := znow.unix - t.unix
|
||||
if secs <= 30 {
|
||||
// right now or in the future
|
||||
// TODO handle time in the future
|
||||
|
@ -323,10 +323,10 @@ pub struct File {
|
||||
pub:
|
||||
path string
|
||||
mod Module
|
||||
stmts []Stmt
|
||||
scope &Scope
|
||||
global_scope &Scope
|
||||
pub mut:
|
||||
stmts []Stmt
|
||||
imports []Import
|
||||
errors []errors.Error
|
||||
warnings []errors.Warning
|
||||
@ -361,9 +361,9 @@ pub struct Ident {
|
||||
pub:
|
||||
language table.Language
|
||||
tok_kind token.Kind
|
||||
mod string
|
||||
pos token.Position
|
||||
pub mut:
|
||||
mod string
|
||||
name string
|
||||
kind IdentKind
|
||||
info IdentInfo
|
||||
@ -753,8 +753,11 @@ pub mut:
|
||||
|
||||
pub struct SizeOf {
|
||||
pub:
|
||||
is_type bool
|
||||
typ table.Type
|
||||
type_name string
|
||||
expr Expr
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct Likely {
|
||||
@ -933,7 +936,9 @@ pub fn (expr Expr) position() token.Position {
|
||||
SelectorExpr {
|
||||
return expr.pos
|
||||
}
|
||||
// ast.SizeOf { }
|
||||
SizeOf {
|
||||
return expr.pos
|
||||
}
|
||||
StringLiteral {
|
||||
return expr.pos
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ pub fn (v Builder) get_user_files() []string {
|
||||
if line[0] == `/` && line[1] == `/` {
|
||||
continue
|
||||
}
|
||||
if line.starts_with('module ') && !line.starts_with('module main') {
|
||||
if line.starts_with('module ') {
|
||||
is_internal_module_test = true
|
||||
break
|
||||
}
|
||||
|
@ -105,15 +105,33 @@ pub fn (mut c Checker) check2(ast_file ast.File) []errors.Error {
|
||||
pub fn (mut c Checker) check_files(ast_files []ast.File) {
|
||||
mut has_main_mod_file := false
|
||||
mut has_main_fn := false
|
||||
for file in ast_files {
|
||||
|
||||
mut files_from_main_module := []&ast.File{}
|
||||
for i in 0..ast_files.len {
|
||||
file := &ast_files[i]
|
||||
c.check(file)
|
||||
if file.mod.name == 'main' {
|
||||
files_from_main_module << file
|
||||
has_main_mod_file = true
|
||||
if c.check_file_in_main(file) {
|
||||
has_main_fn = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if has_main_mod_file && !has_main_fn && files_from_main_module.len > 0 {
|
||||
if c.pref.is_script && !c.pref.is_test {
|
||||
first_main_file := files_from_main_module[0]
|
||||
first_main_file.stmts << ast.FnDecl{
|
||||
name: 'main.main'
|
||||
mod: 'main'
|
||||
file: first_main_file.path
|
||||
return_type: table.void_type
|
||||
}
|
||||
has_main_fn = true
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure fn main is defined in non lib builds
|
||||
if c.pref.build_mode == .build_module || c.pref.is_test {
|
||||
return
|
||||
@ -159,7 +177,7 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool {
|
||||
}
|
||||
}
|
||||
ast.FnDecl {
|
||||
if stmt.name == 'main' {
|
||||
if stmt.name == 'main.main' {
|
||||
has_main_fn = true
|
||||
if stmt.is_pub {
|
||||
c.error('function `main` cannot be declared public', stmt.pos)
|
||||
@ -214,7 +232,7 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool {
|
||||
}
|
||||
|
||||
fn (mut c Checker) check_valid_snake_case(name, identifier string, pos token.Position) {
|
||||
if name[0] == `_` && !c.pref.is_vweb {
|
||||
if !c.pref.is_vweb && ( name[0] == `_` || name.contains('._') ) {
|
||||
c.error('$identifier `$name` cannot start with `_`', pos)
|
||||
}
|
||||
if util.contains_capital(name) {
|
||||
@ -231,8 +249,8 @@ fn stripped_name(name string) string {
|
||||
}
|
||||
|
||||
fn (mut c Checker) check_valid_pascal_case(name, identifier string, pos token.Position) {
|
||||
stripped_name := stripped_name(name)
|
||||
if !stripped_name[0].is_capital() {
|
||||
sname := stripped_name(name)
|
||||
if !sname[0].is_capital() {
|
||||
c.error('$identifier `$name` must begin with capital letter', pos)
|
||||
}
|
||||
}
|
||||
@ -945,7 +963,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||
return table.string_type
|
||||
}
|
||||
if call_expr.generic_type.has_flag(.generic) {
|
||||
if c.mod != '' && c.mod != 'main' {
|
||||
if c.mod != '' {
|
||||
// Need to prepend the module when adding a generic type to a function
|
||||
// `fn_gen_types['mymod.myfn'] == ['string', 'int']`
|
||||
c.table.register_fn_gen_type(c.mod + '.' + fn_name, c.cur_generic_type)
|
||||
@ -975,12 +993,12 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||
call_expr.return_type = ret_type
|
||||
return ret_type
|
||||
}
|
||||
// look for function in format `mod.fn` or `fn` (main/builtin)
|
||||
// look for function in format `mod.fn` or `fn` (builtin)
|
||||
mut f := table.Fn{}
|
||||
mut found := false
|
||||
mut found_in_args := false
|
||||
// try prefix with current module as it would have never gotten prefixed
|
||||
if !fn_name.contains('.') && call_expr.mod !in ['builtin', 'main'] {
|
||||
if !fn_name.contains('.') && call_expr.mod !in ['builtin'] {
|
||||
name_prefixed := '${call_expr.mod}.$fn_name'
|
||||
if f1 := c.table.find_fn(name_prefixed) {
|
||||
call_expr.name = name_prefixed
|
||||
@ -1014,7 +1032,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||
c.error('unknown function: $fn_name', call_expr.pos)
|
||||
return table.void_type
|
||||
}
|
||||
if !found_in_args && call_expr.mod in ['builtin', 'main'] {
|
||||
if !found_in_args {
|
||||
scope := c.file.scope.innermost(call_expr.pos.pos)
|
||||
if _ := scope.find_var(fn_name) {
|
||||
c.error('ambiguous call to: `$fn_name`, may refer to fn `$fn_name` or variable `$fn_name`',
|
||||
@ -1219,7 +1237,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
|
||||
|
||||
pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type) {
|
||||
if or_expr.kind == .propagate {
|
||||
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main' {
|
||||
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main' {
|
||||
c.error('to propagate the optional call, `$c.cur_fn.name` must itself return an optional',
|
||||
or_expr.pos)
|
||||
}
|
||||
@ -1669,7 +1687,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
|
||||
// scope.find(it.name) or {
|
||||
// c.error('undefined ident: `$it.name`', array_init.pos)
|
||||
// }
|
||||
mut full_const_name := if it.mod == 'main' { it.name } else { it.mod + '.' + it.name }
|
||||
mut full_const_name := it.mod + '.' + it.name
|
||||
if obj := c.file.global_scope.find_const(full_const_name) {
|
||||
if cint := const_int_value(obj) {
|
||||
fixed_size = cint
|
||||
@ -2177,7 +2195,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
||||
// TODO: move this
|
||||
if c.const_deps.len > 0 {
|
||||
mut name := ident.name
|
||||
if !name.contains('.') && ident.mod !in ['builtin', 'main'] {
|
||||
if !name.contains('.') && ident.mod !in ['builtin'] {
|
||||
name = '${ident.mod}.$ident.name'
|
||||
}
|
||||
if name == c.const_decl {
|
||||
@ -2255,7 +2273,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
||||
}
|
||||
// prepend mod to look for fn call or const
|
||||
mut name := ident.name
|
||||
if !name.contains('.') && ident.mod !in ['builtin', 'main'] {
|
||||
if !name.contains('.') && ident.mod !in ['builtin'] {
|
||||
name = '${ident.mod}.$ident.name'
|
||||
}
|
||||
if obj := c.file.global_scope.find(name) {
|
||||
@ -2297,6 +2315,17 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
||||
return field.typ
|
||||
}
|
||||
}
|
||||
if ident.kind == .unresolved && ident.mod != 'builtin' {
|
||||
// search in the `builtin` idents, for example
|
||||
// main.compare_f32 may actually be builtin.compare_f32
|
||||
saved_mod := ident.mod
|
||||
ident.mod = 'builtin'
|
||||
builtin_type := c.ident( ident )
|
||||
if builtin_type != table.void_type {
|
||||
return builtin_type
|
||||
}
|
||||
ident.mod = saved_mod
|
||||
}
|
||||
c.error('undefined ident: `$ident.name`', ident.pos)
|
||||
}
|
||||
if c.table.known_type(ident.name) {
|
||||
|
@ -7,6 +7,7 @@ import v.ast
|
||||
import v.table
|
||||
import v.token
|
||||
import strings
|
||||
import v.util
|
||||
|
||||
const (
|
||||
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t',
|
||||
@ -441,10 +442,10 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
||||
f.writeln(' {')
|
||||
match it.kind as k {
|
||||
.insert {
|
||||
f.writeln('\tinsert $it.object_var_name into $it.table_name')
|
||||
f.writeln('\tinsert $it.object_var_name into ${util.strip_mod_name(it.table_name)}')
|
||||
}
|
||||
.update {
|
||||
f.write('\tupdate $it.table_name set ')
|
||||
f.write('\tupdate ${util.strip_mod_name(it.table_name)} set ')
|
||||
for i, col in it.updated_columns {
|
||||
f.write('$col = ')
|
||||
f.expr(it.update_exprs[i])
|
||||
@ -888,13 +889,19 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||
f.write(node.field_name)
|
||||
}
|
||||
ast.SizeOf {
|
||||
f.write('sizeof(')
|
||||
if node.type_name != '' {
|
||||
f.write(node.type_name)
|
||||
if node.is_type {
|
||||
f.write('sizeof(')
|
||||
if node.type_name != '' {
|
||||
f.write(node.type_name)
|
||||
} else {
|
||||
f.write(f.type_to_str(node.typ))
|
||||
}
|
||||
f.write(')')
|
||||
} else {
|
||||
f.write(f.type_to_str(node.typ))
|
||||
f.write('sizeof(')
|
||||
f.expr(node.expr)
|
||||
f.write(')')
|
||||
}
|
||||
f.write(')')
|
||||
}
|
||||
ast.SqlExpr {
|
||||
// sql app.db { select from Contributor where repo == id && user == 0 }
|
||||
@ -918,7 +925,7 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
||||
f.write(' ')
|
||||
}
|
||||
}
|
||||
f.write('from $node.table_name')
|
||||
f.write('from ${util.strip_mod_name(node.table_name)}')
|
||||
f.write(' ')
|
||||
if node.has_where {
|
||||
f.write('where ')
|
||||
|
@ -83,7 +83,6 @@ mut:
|
||||
attrs []string // attributes before next decl stmt
|
||||
is_builtin_mod bool
|
||||
hotcode_fn_names []string
|
||||
fn_main &ast.FnDecl // the FnDecl of the main function. Needed in order to generate the main function code *last*
|
||||
cur_fn &ast.FnDecl = 0
|
||||
cur_generic_type table.Type // `int`, `string`, etc in `foo<T>()`
|
||||
sql_i int
|
||||
@ -93,6 +92,7 @@ mut:
|
||||
inside_return bool
|
||||
strs_to_free string
|
||||
inside_call bool
|
||||
has_main bool
|
||||
}
|
||||
|
||||
const (
|
||||
@ -126,8 +126,6 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||
table: table
|
||||
pref: pref
|
||||
fn_decl: 0
|
||||
fn_main: 0
|
||||
cur_fn: 0
|
||||
autofree: true
|
||||
indent: -1
|
||||
module_built: pref.path.after('vlib/')
|
||||
@ -285,10 +283,8 @@ pub fn (mut g Gen) finish() {
|
||||
if g.pref.is_livemain || g.pref.is_liveshared {
|
||||
g.generate_hotcode_reloader_code()
|
||||
}
|
||||
if g.fn_main != voidptr(0) {
|
||||
g.out.writeln('')
|
||||
g.fn_decl = g.fn_main
|
||||
g.gen_fn_decl(g.fn_main)
|
||||
if !g.pref.is_test {
|
||||
g.gen_c_main()
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,12 +297,12 @@ pub fn (mut g Gen) write_typeof_functions() {
|
||||
tidx := g.table.find_type_idx(typ.name)
|
||||
g.writeln('char * v_typeof_sumtype_${tidx}(int sidx) { /* $typ.name */ ')
|
||||
g.writeln(' switch(sidx) {')
|
||||
g.writeln(' case $tidx: return "$typ.name";')
|
||||
g.writeln(' case $tidx: return "${util.strip_main_name(typ.name)}";')
|
||||
for v in sum_info.variants {
|
||||
subtype := g.table.get_type_symbol(v)
|
||||
g.writeln(' case $v: return "$subtype.name";')
|
||||
g.writeln(' case $v: return "${util.strip_main_name(subtype.name)}";')
|
||||
}
|
||||
g.writeln(' default: return "unknown $typ.name";')
|
||||
g.writeln(' default: return "unknown ${util.strip_main_name(typ.name)}";')
|
||||
g.writeln(' }')
|
||||
g.writeln('}')
|
||||
}
|
||||
@ -383,7 +379,7 @@ fn (mut g Gen) register_optional(t table.Type) string {
|
||||
g.typedefs2.writeln('typedef struct $styp $styp;')
|
||||
g.options.write(g.optional_type_text(styp, base))
|
||||
g.options.writeln(';\n')
|
||||
g.optionals << styp
|
||||
g.optionals << styp.clone()
|
||||
}
|
||||
return styp
|
||||
}
|
||||
@ -392,7 +388,7 @@ fn (mut g Gen) register_optional(t table.Type) string {
|
||||
// i.e. it's always just Cat, not Cat_ptr:
|
||||
fn (g &Gen) cc_type(t table.Type) string {
|
||||
sym := g.table.get_type_symbol(g.unwrap_generic(t))
|
||||
mut styp := sym.name.replace('.', '__')
|
||||
mut styp := util.no_dots(sym.name)
|
||||
if sym.kind == .struct_ {
|
||||
info := sym.info as table.Struct
|
||||
if info.generic_types.len > 0 {
|
||||
@ -436,21 +432,20 @@ typedef struct {
|
||||
match typ.kind {
|
||||
.alias {
|
||||
parent := &g.table.types[typ.parent_idx]
|
||||
styp := typ.name.replace('.', '__')
|
||||
styp := util.no_dots(typ.name)
|
||||
is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.`
|
||||
parent_styp := if is_c_parent { 'struct ' + parent.name[2..].replace('.', '__') } else { parent.name.replace('.',
|
||||
'__') }
|
||||
parent_styp := if is_c_parent { 'struct ' + util.no_dots(parent.name[2..]) } else { util.no_dots(parent.name) }
|
||||
g.type_definitions.writeln('typedef $parent_styp $styp;')
|
||||
}
|
||||
.array {
|
||||
styp := typ.name.replace('.', '__')
|
||||
styp := util.no_dots(typ.name)
|
||||
g.type_definitions.writeln('typedef array $styp;')
|
||||
}
|
||||
.interface_ {
|
||||
g.type_definitions.writeln('typedef _Interface ${c_name(typ.name)};')
|
||||
}
|
||||
.map {
|
||||
styp := typ.name.replace('.', '__')
|
||||
styp := util.no_dots(typ.name)
|
||||
g.type_definitions.writeln('typedef map $styp;')
|
||||
}
|
||||
.function {
|
||||
@ -462,7 +457,7 @@ typedef struct {
|
||||
not_anon := !info.is_anon
|
||||
if !info.has_decl && !is_multi && (not_anon || is_fn_sig) {
|
||||
fn_name := if func.language == .c {
|
||||
func.name.replace('.', '__')
|
||||
util.no_dots(func.name)
|
||||
} else if info.is_anon {
|
||||
typ.name
|
||||
} else {
|
||||
@ -492,7 +487,7 @@ pub fn (mut g Gen) write_multi_return_types() {
|
||||
if typ.kind != .multi_return {
|
||||
continue
|
||||
}
|
||||
name := typ.name.replace('.', '__')
|
||||
name := util.no_dots(typ.name)
|
||||
info := typ.info as table.MultiReturn
|
||||
g.type_definitions.writeln('typedef struct {')
|
||||
// TODO copy pasta StructDecl
|
||||
@ -643,7 +638,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
g.defer_stmts << defer_stmt
|
||||
}
|
||||
ast.EnumDecl {
|
||||
enum_name := node.name.replace('.', '__')
|
||||
enum_name := util.no_dots(node.name)
|
||||
g.enum_typedefs.writeln('typedef enum {')
|
||||
mut cur_enum_expr := ''
|
||||
mut cur_enum_offset := 0
|
||||
@ -688,23 +683,21 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
println('build module `$g.module_built` fn `$node.name`')
|
||||
}
|
||||
}
|
||||
keep_fn_decl := g.fn_decl
|
||||
g.fn_decl = node // &it
|
||||
if node.name == 'main' {
|
||||
// just remember `it`; main code will be generated in finish()
|
||||
g.fn_main = node
|
||||
} else {
|
||||
if node.name == 'backtrace' ||
|
||||
node.name == 'backtrace_symbols' ||
|
||||
node.name == 'backtrace_symbols_fd' {
|
||||
g.write('\n#ifndef __cplusplus\n')
|
||||
}
|
||||
g.gen_fn_decl(node)
|
||||
if node.name == 'backtrace' ||
|
||||
node.name == 'backtrace_symbols' ||
|
||||
node.name == 'backtrace_symbols_fd' {
|
||||
g.write('\n#endif\n')
|
||||
}
|
||||
keep_fn_decl := g.fn_decl
|
||||
g.fn_decl = node
|
||||
if node.name == 'main.main' {
|
||||
g.has_main = true
|
||||
}
|
||||
if node.name == 'backtrace' ||
|
||||
node.name == 'backtrace_symbols' ||
|
||||
node.name == 'backtrace_symbols_fd' {
|
||||
g.write('\n#ifndef __cplusplus\n')
|
||||
}
|
||||
g.gen_fn_decl(node)
|
||||
if node.name == 'backtrace' ||
|
||||
node.name == 'backtrace_symbols' ||
|
||||
node.name == 'backtrace_symbols_fd' {
|
||||
g.write('\n#endif\n')
|
||||
}
|
||||
g.fn_decl = keep_fn_decl
|
||||
if skip {
|
||||
@ -786,7 +779,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
g.sql_stmt(node)
|
||||
}
|
||||
ast.StructDecl {
|
||||
name := if node.language == .c { node.name.replace('.', '__') } else { c_name(node.name) }
|
||||
name := if node.language == .c { util.no_dots(node.name) } else { c_name(node.name) }
|
||||
// g.writeln('typedef struct {')
|
||||
// for field in it.fields {
|
||||
// field_type_sym := g.table.get_type_symbol(field.typ)
|
||||
@ -967,11 +960,11 @@ fn (mut g Gen) gen_assert_stmt(a ast.AssertStmt) {
|
||||
g.writeln('{')
|
||||
g.writeln(' g_test_oks++;')
|
||||
metaname_ok := g.gen_assert_metainfo(a)
|
||||
g.writeln(' cb_assertion_ok(&$metaname_ok);')
|
||||
g.writeln(' main__cb_assertion_ok(&$metaname_ok);')
|
||||
g.writeln('} else {')
|
||||
g.writeln(' g_test_fails++;')
|
||||
metaname_fail := g.gen_assert_metainfo(a)
|
||||
g.writeln(' cb_assertion_failed(&$metaname_fail);')
|
||||
g.writeln(' main__cb_assertion_failed(&$metaname_fail);')
|
||||
g.writeln(' longjmp(g_jump_buffer, 1);')
|
||||
g.writeln(' // TODO')
|
||||
g.writeln(' // Maybe print all vars in a test function if it fails?')
|
||||
@ -1605,24 +1598,28 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||
// Only used in IndexExpr
|
||||
}
|
||||
ast.SizeOf {
|
||||
mut styp := node.type_name
|
||||
if node.type_name == '' {
|
||||
styp = g.typ(node.typ)
|
||||
} else {
|
||||
sym := g.table.get_type_symbol(node.typ)
|
||||
if sym.kind == .struct_ {
|
||||
info := sym.info as table.Struct
|
||||
if !info.is_typedef {
|
||||
styp = 'struct ' + styp
|
||||
if node.is_type {
|
||||
mut styp := node.type_name
|
||||
if styp.starts_with('C.') {
|
||||
styp = styp[2..]
|
||||
}
|
||||
if node.type_name == '' {
|
||||
styp = g.typ(node.typ)
|
||||
} else {
|
||||
sym := g.table.get_type_symbol(node.typ)
|
||||
if sym.kind == .struct_ {
|
||||
info := sym.info as table.Struct
|
||||
if !info.is_typedef {
|
||||
styp = 'struct ' + styp
|
||||
}
|
||||
}
|
||||
}
|
||||
g.write('/*SizeOfType*/ sizeof(${util.no_dots(styp)})')
|
||||
} else {
|
||||
g.write('/*SizeOfVar*/ sizeof(')
|
||||
g.expr(node.expr)
|
||||
g.write(')')
|
||||
}
|
||||
/*
|
||||
if styp.starts_with('C__') {
|
||||
styp = styp[3..]
|
||||
}
|
||||
*/
|
||||
g.write('sizeof($styp)')
|
||||
}
|
||||
ast.SqlExpr {
|
||||
g.sql_select_expr(node)
|
||||
@ -1685,7 +1682,7 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
||||
} else if sym.kind == .array_fixed {
|
||||
fixed_info := sym.info as table.ArrayFixed
|
||||
typ_name := g.table.get_type_name(fixed_info.elem_type)
|
||||
g.write('tos_lit("[$fixed_info.size]$typ_name")')
|
||||
g.write('tos_lit("[$fixed_info.size]${util.strip_main_name(typ_name)}")')
|
||||
} else if sym.kind == .function {
|
||||
info := sym.info as table.FnType
|
||||
fn_info := info.func
|
||||
@ -1694,15 +1691,15 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
||||
if i > 0 {
|
||||
repr += ', '
|
||||
}
|
||||
repr += g.table.get_type_name(arg.typ)
|
||||
repr += util.strip_main_name(g.table.get_type_name(arg.typ))
|
||||
}
|
||||
repr += ')'
|
||||
if fn_info.return_type != table.void_type {
|
||||
repr += ' ${g.table.get_type_name(fn_info.return_type)}'
|
||||
repr += ' ${util.strip_main_name(g.table.get_type_name(fn_info.return_type))}'
|
||||
}
|
||||
g.write('tos_lit("$repr")')
|
||||
} else {
|
||||
g.write('tos_lit("$sym.name")')
|
||||
g.write('tos_lit("${util.strip_main_name(sym.name)}")')
|
||||
}
|
||||
}
|
||||
|
||||
@ -2039,7 +2036,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||
return
|
||||
}
|
||||
if node.name.starts_with('C.') {
|
||||
g.write(node.name[2..].replace('.', '__'))
|
||||
g.write(util.no_dots(node.name[2..]))
|
||||
return
|
||||
}
|
||||
if node.kind == .constant { // && !node.name.starts_with('g_') {
|
||||
@ -2308,10 +2305,6 @@ fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
||||
}
|
||||
|
||||
fn (mut g Gen) return_statement(node ast.Return) {
|
||||
if g.fn_decl.name == 'main' {
|
||||
g.writeln('return 0;')
|
||||
return
|
||||
}
|
||||
if node.exprs.len > 0 {
|
||||
// skip `retun $vweb.html()`
|
||||
if node.exprs[0] is ast.ComptimeCall {
|
||||
@ -2772,7 +2765,7 @@ fn (mut g Gen) write_init_function() {
|
||||
for mod_name in g.table.imports {
|
||||
init_fn_name := '${mod_name}.init'
|
||||
if _ := g.table.find_fn(init_fn_name) {
|
||||
mod_c_name := mod_name.replace('.', '__')
|
||||
mod_c_name := util.no_dots(mod_name)
|
||||
init_fn_c_name := '${mod_c_name}__init'
|
||||
g.writeln('\t${init_fn_c_name}();')
|
||||
}
|
||||
@ -2832,7 +2825,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
||||
continue
|
||||
}
|
||||
// sym := g.table.get_type_symbol(typ)
|
||||
mut name := typ.name.replace('.', '__')
|
||||
mut name := util.no_dots(typ.name)
|
||||
match typ.info as info {
|
||||
table.Struct {
|
||||
if info.generic_types.len > 0 {
|
||||
@ -2896,7 +2889,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
||||
}
|
||||
table.ArrayFixed {
|
||||
// .array_fixed {
|
||||
styp := typ.name.replace('.', '__')
|
||||
styp := util.no_dots(typ.name)
|
||||
// array_fixed_char_300 => char x[300]
|
||||
mut fixed := styp[12..]
|
||||
len := styp.after('_')
|
||||
@ -3073,12 +3066,12 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
|
||||
}
|
||||
ast.Ident {
|
||||
if it.kind == .function {
|
||||
g.write('${it.name}(it)')
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
} else if it.kind == .variable {
|
||||
var_info := it.var_info()
|
||||
sym := g.table.get_type_symbol(var_info.typ)
|
||||
if sym.kind == .function {
|
||||
g.write('${it.name}(it)')
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
@ -3125,12 +3118,12 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
|
||||
}
|
||||
ast.Ident {
|
||||
if it.kind == .function {
|
||||
g.write('${it.name}(it)')
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
} else if it.kind == .variable {
|
||||
var_info := it.var_info()
|
||||
sym_t := g.table.get_type_symbol(var_info.typ)
|
||||
if sym_t.kind == .function {
|
||||
g.write('${it.name}(it)')
|
||||
g.write('${c_name(it.name)}(it)')
|
||||
} else {
|
||||
g.expr(node.args[0].expr)
|
||||
}
|
||||
@ -3283,7 +3276,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
|
||||
g.stmts(stmts)
|
||||
}
|
||||
} else if or_block.kind == .propagate {
|
||||
if g.file.mod.name == 'main' && g.cur_fn.name == 'main' {
|
||||
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
|
||||
// In main(), an `opt()?` call is sugar for `opt() or { panic(err) }`
|
||||
if g.pref.is_debug {
|
||||
paline, pafile, pamod, pafn := g.panic_debug_info(or_block.pos)
|
||||
@ -3471,7 +3464,7 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) string {
|
||||
|
||||
[inline]
|
||||
fn c_name(name_ string) string {
|
||||
name := name_.replace('.', '__')
|
||||
name := util.no_dots(name_)
|
||||
if name in c_reserved {
|
||||
return 'v_$name'
|
||||
}
|
||||
@ -3482,7 +3475,7 @@ fn (g Gen) type_default(typ table.Type) string {
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
if sym.kind == .array {
|
||||
elem_sym := g.typ(sym.array_info().elem_type)
|
||||
mut elem_type_str := elem_sym.replace('.', '__')
|
||||
mut elem_type_str := util.no_dots(elem_sym)
|
||||
if elem_type_str.starts_with('C__') {
|
||||
elem_type_str = elem_type_str[3..]
|
||||
}
|
||||
@ -3562,21 +3555,21 @@ pub fn (mut g Gen) write_tests_main() {
|
||||
g.writeln('')
|
||||
all_tfuncs := g.get_all_test_function_names()
|
||||
if g.pref.is_stats {
|
||||
g.writeln('\tBenchedTests bt = start_testing($all_tfuncs.len, tos_lit("$g.pref.path"));')
|
||||
g.writeln('\tmain__BenchedTests bt = main__start_testing($all_tfuncs.len, tos_lit("$g.pref.path"));')
|
||||
}
|
||||
for t in all_tfuncs {
|
||||
g.writeln('')
|
||||
if g.pref.is_stats {
|
||||
g.writeln('\tBenchedTests_testing_step_start(&bt, tos_lit("$t"));')
|
||||
g.writeln('\tmain__BenchedTests_testing_step_start(&bt, tos_lit("$t"));')
|
||||
}
|
||||
g.writeln('\tif (!setjmp(g_jump_buffer)) ${t}();')
|
||||
if g.pref.is_stats {
|
||||
g.writeln('\tBenchedTests_testing_step_end(&bt);')
|
||||
g.writeln('\tmain__BenchedTests_testing_step_end(&bt);')
|
||||
}
|
||||
}
|
||||
g.writeln('')
|
||||
if g.pref.is_stats {
|
||||
g.writeln('\tBenchedTests_end_testing(&bt);')
|
||||
g.writeln('\tmain__BenchedTests_end_testing(&bt);')
|
||||
}
|
||||
g.writeln('')
|
||||
if g.autofree {
|
||||
@ -3628,7 +3621,7 @@ fn (g Gen) get_all_test_function_names() []string {
|
||||
}
|
||||
mut all_tfuncs_c := []string{}
|
||||
for f in all_tfuncs {
|
||||
all_tfuncs_c << f.replace('.', '__')
|
||||
all_tfuncs_c << util.no_dots(f)
|
||||
}
|
||||
return all_tfuncs_c
|
||||
}
|
||||
@ -3640,12 +3633,12 @@ fn (g Gen) is_importing_os() bool {
|
||||
fn (mut g Gen) go_stmt(node ast.GoStmt) {
|
||||
tmp := g.new_tmp_var()
|
||||
expr := node.call_expr as ast.CallExpr
|
||||
mut name := expr.name // .replace('.', '__')
|
||||
mut name := expr.name // util.no_dots(expr.name)
|
||||
if expr.is_method {
|
||||
receiver_sym := g.table.get_type_symbol(expr.receiver_type)
|
||||
name = receiver_sym.name + '_' + name
|
||||
}
|
||||
name = name.replace('.', '__')
|
||||
name = util.no_dots(name)
|
||||
g.writeln('// go')
|
||||
wrapper_struct_name := 'thread_arg_' + name
|
||||
wrapper_fn_name := name + '_thread_wrapper'
|
||||
@ -3750,7 +3743,7 @@ fn (mut g Gen) is_expr(node ast.InfixExpr) {
|
||||
// `_Animal_Dog_index`
|
||||
sub_type := node.right as ast.Type
|
||||
sub_sym := g.table.get_type_symbol(sub_type.typ)
|
||||
g.write('_${sym.name}_${sub_sym.name}_index')
|
||||
g.write('_${c_name(sym.name)}_${c_name(sub_sym.name)}_index')
|
||||
return
|
||||
} else if sym.kind == .sum_type {
|
||||
g.write('typ $eq ')
|
||||
@ -3859,7 +3852,7 @@ fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_str_for_enum(info table.Enum, styp, str_fn_name string) {
|
||||
s := styp.replace('.', '__')
|
||||
s := util.no_dots(styp)
|
||||
g.type_definitions.writeln('string ${str_fn_name}($styp it); // auto')
|
||||
g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { /* gen_str_for_enum */')
|
||||
g.auto_str_funcs.writeln('\tswitch(it) {')
|
||||
@ -3896,6 +3889,7 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
||||
deref_typ := styp
|
||||
g.auto_str_funcs.writeln('\t$deref_typ *it = &x;')
|
||||
}
|
||||
clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name)
|
||||
// generate ident / indent length = 4 spaces
|
||||
g.auto_str_funcs.writeln('\tstring indents = tos_lit("");')
|
||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {')
|
||||
|
65
vlib/v/gen/cmain.v
Normal file
65
vlib/v/gen/cmain.v
Normal file
@ -0,0 +1,65 @@
|
||||
module gen
|
||||
|
||||
pub fn (mut g Gen) gen_c_main() {
|
||||
if !g.has_main {
|
||||
return
|
||||
}
|
||||
if g.pref.is_liveshared {
|
||||
return
|
||||
}
|
||||
g.out.writeln('')
|
||||
g.gen_c_main_header()
|
||||
g.writeln('\tmain__main();')
|
||||
g.gen_c_main_footer()
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_c_main_header() {
|
||||
if g.pref.os == .windows {
|
||||
if g.is_gui_app() {
|
||||
// GUI application
|
||||
g.writeln('int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, LPWSTR cmd_line, int show_cmd){')
|
||||
} else {
|
||||
// Console application
|
||||
g.writeln('int wmain(int ___argc, wchar_t* ___argv[], wchar_t* ___envp[]){')
|
||||
}
|
||||
} else {
|
||||
g.writeln('int main(int ___argc, char** ___argv){')
|
||||
}
|
||||
if g.pref.os == .windows && g.is_gui_app() {
|
||||
g.writeln('\ttypedef LPWSTR*(WINAPI *cmd_line_to_argv)(LPCWSTR, int*);')
|
||||
g.writeln('\tHMODULE shell32_module = LoadLibrary(L"shell32.dll");')
|
||||
g.writeln('\tcmd_line_to_argv CommandLineToArgvW = (cmd_line_to_argv)GetProcAddress(shell32_module, "CommandLineToArgvW");')
|
||||
g.writeln('\tint ___argc;')
|
||||
g.writeln('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);')
|
||||
}
|
||||
g.writeln('\t_vinit();')
|
||||
|
||||
if g.pref.is_prof {
|
||||
g.writeln('')
|
||||
g.writeln('\tatexit(vprint_profile_stats);')
|
||||
g.writeln('')
|
||||
}
|
||||
|
||||
if g.is_importing_os() {
|
||||
if g.autofree {
|
||||
g.writeln('free(_const_os__args.data); // empty, inited in _vinit()')
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
g.writeln('\t_const_os__args = os__init_os_args_wide(___argc, ___argv);')
|
||||
} else {
|
||||
g.writeln('\t_const_os__args = os__init_os_args(___argc, (byteptr*)___argv);')
|
||||
}
|
||||
}
|
||||
if g.pref.is_livemain {
|
||||
g.generate_hotcode_reloading_main_caller()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_c_main_footer() {
|
||||
if g.autofree {
|
||||
g.writeln('\t_vcleanup();')
|
||||
}
|
||||
|
||||
g.writeln('\treturn 0;')
|
||||
g.writeln('}')
|
||||
}
|
@ -5,6 +5,7 @@ module gen
|
||||
|
||||
import v.ast
|
||||
import v.table
|
||||
import v.util
|
||||
|
||||
fn (g &Gen) comptime_call(node ast.ComptimeCall) {
|
||||
if node.is_vweb {
|
||||
@ -12,7 +13,7 @@ fn (g &Gen) comptime_call(node ast.ComptimeCall) {
|
||||
if stmt is ast.FnDecl {
|
||||
fn_decl := stmt as ast.FnDecl
|
||||
// insert stmts from vweb_tmpl fn
|
||||
if fn_decl.name.starts_with('vweb_tmpl') {
|
||||
if fn_decl.name.starts_with('main.vweb_tmpl') {
|
||||
g.inside_vweb_tmpl = true
|
||||
g.stmts(fn_decl.stmts)
|
||||
g.inside_vweb_tmpl = false
|
||||
@ -40,7 +41,7 @@ fn (g &Gen) comptime_call(node ast.ComptimeCall) {
|
||||
g.write(' else ')
|
||||
}
|
||||
g.write('if (string_eq($node.method_name, tos_lit("$method.name"))) ')
|
||||
g.write('${node.sym.name}_${method.name}($amp ')
|
||||
g.write('${util.no_dots(node.sym.name)}_${method.name}($amp ')
|
||||
g.expr(node.left)
|
||||
g.writeln(');')
|
||||
j++
|
||||
@ -66,5 +67,5 @@ fn (mut g Gen) comp_if(it ast.CompIf) {
|
||||
g.stmts(it.else_stmts)
|
||||
g.defer_ifdef = ''
|
||||
}
|
||||
g.writeln('\n// } $it.val\n#endif\n')
|
||||
g.writeln('\n#endif\n// } $it.val\n')
|
||||
}
|
||||
|
246
vlib/v/gen/fn.v
246
vlib/v/gen/fn.v
@ -15,12 +15,6 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
// if g.fileis('vweb.v') {
|
||||
// println('\ngen_fn_decl() $it.name $it.is_generic $g.cur_generic_type')
|
||||
// }
|
||||
former_cur_fn := g.cur_fn
|
||||
g.cur_fn = &it
|
||||
defer {
|
||||
g.cur_fn = former_cur_fn
|
||||
}
|
||||
is_main := it.name == 'main'
|
||||
if it.is_generic && g.cur_generic_type == 0 { // need the cur_generic_type check to avoid inf. recursion
|
||||
// loop thru each generic type and generate a function
|
||||
for gen_type in g.table.fn_gen_types[it.name] {
|
||||
@ -34,9 +28,6 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
g.cur_generic_type = 0
|
||||
return
|
||||
}
|
||||
if is_main && g.pref.is_liveshared {
|
||||
return
|
||||
}
|
||||
fn_start_pos := g.out.len
|
||||
msvc_attrs := g.write_fn_attrs()
|
||||
// Live
|
||||
@ -49,165 +40,108 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
|
||||
eprintln('INFO: compile with `v -live $g.pref.path `, if you want to use the [live] function $it.name .')
|
||||
}
|
||||
//
|
||||
if is_main {
|
||||
if g.pref.os == .windows {
|
||||
if g.is_gui_app() {
|
||||
// GUI application
|
||||
g.writeln('int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, LPWSTR cmd_line, int show_cmd){')
|
||||
g.last_fn_c_name = 'wWinMain'
|
||||
} else {
|
||||
// Console application
|
||||
g.writeln('int wmain(int ___argc, wchar_t* ___argv[], wchar_t* ___envp[]){')
|
||||
g.last_fn_c_name = 'wmain'
|
||||
}
|
||||
} else {
|
||||
g.writeln('int main(int ___argc, char** ___argv){')
|
||||
g.last_fn_c_name = it.name
|
||||
mut name := it.name
|
||||
if name[0] in [`+`, `-`, `*`, `/`, `%`] {
|
||||
name = util.replace_op(name)
|
||||
}
|
||||
if it.is_method {
|
||||
name = g.table.get_type_symbol(it.receiver.typ).name + '_' + name
|
||||
}
|
||||
if it.language == .c {
|
||||
name = util.no_dots(name)
|
||||
} else {
|
||||
name = c_name(name)
|
||||
}
|
||||
mut type_name := g.typ(it.return_type)
|
||||
if g.cur_generic_type != 0 {
|
||||
// foo<T>() => foo_int(), foo_string() etc
|
||||
gen_name := g.typ(g.cur_generic_type)
|
||||
name += '_' + gen_name
|
||||
type_name = type_name.replace('T', gen_name)
|
||||
}
|
||||
// if g.pref.show_cc && it.is_builtin {
|
||||
// println(name)
|
||||
// }
|
||||
// type_name := g.table.Type_to_str(it.return_type)
|
||||
// Live functions are protected by a mutex, because otherwise they
|
||||
// can be changed by the live reload thread, *while* they are
|
||||
// running, with unpredictable results (usually just crashing).
|
||||
// For this purpose, the actual body of the live function,
|
||||
// is put under a non publicly accessible function, that is prefixed
|
||||
// with 'impl_live_' .
|
||||
if is_livemain {
|
||||
g.hotcode_fn_names << name
|
||||
}
|
||||
mut impl_fn_name := name
|
||||
if is_live_wrap {
|
||||
impl_fn_name = 'impl_live_${name}'
|
||||
}
|
||||
g.last_fn_c_name = impl_fn_name
|
||||
//
|
||||
if is_live_wrap {
|
||||
if is_livemain {
|
||||
g.definitions.write('$type_name (* $impl_fn_name)(')
|
||||
g.write('$type_name no_impl_${name}(')
|
||||
}
|
||||
if is_liveshared {
|
||||
g.definitions.write('$type_name ${impl_fn_name}(')
|
||||
g.write('$type_name ${impl_fn_name}(')
|
||||
}
|
||||
} else {
|
||||
mut name := it.name
|
||||
if name[0] in [`+`, `-`, `*`, `/`, `%`] {
|
||||
name = util.replace_op(name)
|
||||
}
|
||||
if it.is_method {
|
||||
name = g.table.get_type_symbol(it.receiver.typ).name + '_' + name
|
||||
}
|
||||
if it.language == .c {
|
||||
name = name.replace('.', '__')
|
||||
} else {
|
||||
name = c_name(name)
|
||||
}
|
||||
mut type_name := g.typ(it.return_type)
|
||||
if g.cur_generic_type != 0 {
|
||||
// foo<T>() => foo_int(), foo_string() etc
|
||||
gen_name := g.typ(g.cur_generic_type)
|
||||
name += '_' + gen_name
|
||||
// type_name = type_name.replace('T', gen_name)
|
||||
}
|
||||
// if g.pref.show_cc && it.is_builtin {
|
||||
// println(name)
|
||||
// }
|
||||
// type_name := g.table.Type_to_str(it.return_type)
|
||||
// Live functions are protected by a mutex, because otherwise they
|
||||
// can be changed by the live reload thread, *while* they are
|
||||
// running, with unpredictable results (usually just crashing).
|
||||
// For this purpose, the actual body of the live function,
|
||||
// is put under a non publicly accessible function, that is prefixed
|
||||
// with 'impl_live_' .
|
||||
if is_livemain {
|
||||
g.hotcode_fn_names << name
|
||||
}
|
||||
mut impl_fn_name := if is_live_wrap { 'impl_live_$name' } else { name }
|
||||
g.last_fn_c_name = impl_fn_name
|
||||
//
|
||||
if is_live_wrap {
|
||||
if is_livemain {
|
||||
g.definitions.write('$type_name (* $impl_fn_name)(')
|
||||
g.write('$type_name no_impl_${name}(')
|
||||
}
|
||||
if is_liveshared {
|
||||
g.definitions.write('$type_name ${impl_fn_name}(')
|
||||
g.write('$type_name ${impl_fn_name}(')
|
||||
}
|
||||
} else {
|
||||
if !(it.is_pub || g.pref.is_debug) {
|
||||
g.write('static ')
|
||||
g.definitions.write('static ')
|
||||
}
|
||||
fn_header := if msvc_attrs.len > 0 { '$type_name $msvc_attrs ${name}(' } else { '$type_name ${name}(' }
|
||||
g.definitions.write(fn_header)
|
||||
g.write(fn_header)
|
||||
}
|
||||
fargs, fargtypes := g.fn_args(it.args, it.is_variadic)
|
||||
if it.no_body || (g.pref.use_cache && it.is_builtin) {
|
||||
// Just a function header. Builtin function bodies are defined in builtin.o
|
||||
g.definitions.writeln(');')
|
||||
g.writeln(');')
|
||||
return
|
||||
if !(it.is_pub || g.pref.is_debug) {
|
||||
g.write('static ')
|
||||
g.definitions.write('static ')
|
||||
}
|
||||
fn_header := if msvc_attrs.len > 0 { '$type_name $msvc_attrs ${name}(' } else { '$type_name ${name}(' }
|
||||
g.definitions.write(fn_header)
|
||||
g.write(fn_header)
|
||||
}
|
||||
fargs, fargtypes := g.fn_args(it.args, it.is_variadic)
|
||||
if it.no_body || (g.pref.use_cache && it.is_builtin) {
|
||||
// Just a function header. Builtin function bodies are defined in builtin.o
|
||||
g.definitions.writeln(');')
|
||||
g.writeln(') {')
|
||||
if is_live_wrap {
|
||||
// The live function just calls its implementation dual, while ensuring
|
||||
// that the call is wrapped by the mutex lock & unlock calls.
|
||||
// Adding the mutex lock/unlock inside the body of the implementation
|
||||
// function is not reliable, because the implementation function can do
|
||||
// an early exit, which will leave the mutex locked.
|
||||
mut fn_args_list := []string{}
|
||||
for ia, fa in fargs {
|
||||
fn_args_list << '${fargtypes[ia]} $fa'
|
||||
}
|
||||
mut live_fncall := '${impl_fn_name}(' + fargs.join(', ') + ');'
|
||||
mut live_fnreturn := ''
|
||||
if type_name != 'void' {
|
||||
live_fncall = '$type_name res = $live_fncall'
|
||||
live_fnreturn = 'return res;'
|
||||
}
|
||||
g.definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') +
|
||||
');')
|
||||
g.hotcode_definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') +
|
||||
'){')
|
||||
g.hotcode_definitions.writeln(' pthread_mutex_lock(&live_fn_mutex);')
|
||||
g.hotcode_definitions.writeln(' $live_fncall')
|
||||
g.hotcode_definitions.writeln(' pthread_mutex_unlock(&live_fn_mutex);')
|
||||
g.hotcode_definitions.writeln(' $live_fnreturn')
|
||||
g.hotcode_definitions.writeln('}')
|
||||
}
|
||||
g.writeln(');')
|
||||
return
|
||||
}
|
||||
if is_main {
|
||||
if g.pref.os == .windows && g.is_gui_app() {
|
||||
g.writeln('\ttypedef LPWSTR*(WINAPI *cmd_line_to_argv)(LPCWSTR, int*);')
|
||||
g.writeln('\tHMODULE shell32_module = LoadLibrary(L"shell32.dll");')
|
||||
g.writeln('\tcmd_line_to_argv CommandLineToArgvW = (cmd_line_to_argv)GetProcAddress(shell32_module, "CommandLineToArgvW");')
|
||||
g.writeln('\tint ___argc;')
|
||||
g.writeln('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);')
|
||||
g.definitions.writeln(');')
|
||||
g.writeln(') {')
|
||||
if is_live_wrap {
|
||||
// The live function just calls its implementation dual, while ensuring
|
||||
// that the call is wrapped by the mutex lock & unlock calls.
|
||||
// Adding the mutex lock/unlock inside the body of the implementation
|
||||
// function is not reliable, because the implementation function can do
|
||||
// an early exit, which will leave the mutex locked.
|
||||
mut fn_args_list := []string{}
|
||||
for ia, fa in fargs {
|
||||
fn_args_list << '${fargtypes[ia]} ${fa}'
|
||||
}
|
||||
g.writeln('\t_vinit();')
|
||||
if g.is_importing_os() {
|
||||
if g.autofree {
|
||||
g.writeln('free(_const_os__args.data); // empty, inited in _vinit()')
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
g.writeln('\t_const_os__args = os__init_os_args_wide(___argc, ___argv);')
|
||||
}
|
||||
//
|
||||
else {
|
||||
g.writeln('\t_const_os__args = os__init_os_args(___argc, (byteptr*)___argv);')
|
||||
}
|
||||
mut live_fncall := '${impl_fn_name}(' + fargs.join(', ') + ');'
|
||||
mut live_fnreturn := ''
|
||||
if type_name != 'void' {
|
||||
live_fncall = '${type_name} res = ${live_fncall}'
|
||||
live_fnreturn = 'return res;'
|
||||
}
|
||||
}
|
||||
if g.pref.is_livemain && is_main {
|
||||
g.generate_hotcode_reloading_main_caller()
|
||||
g.definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') + ');')
|
||||
g.hotcode_definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') +
|
||||
'){')
|
||||
g.hotcode_definitions.writeln(' pthread_mutex_lock(&live_fn_mutex);')
|
||||
g.hotcode_definitions.writeln(' $live_fncall')
|
||||
g.hotcode_definitions.writeln(' pthread_mutex_unlock(&live_fn_mutex);')
|
||||
g.hotcode_definitions.writeln(' $live_fnreturn')
|
||||
g.hotcode_definitions.writeln('}')
|
||||
}
|
||||
// Profiling mode? Start counting at the beginning of the function (save current time).
|
||||
if g.pref.is_prof {
|
||||
g.profile_fn(it.name, is_main)
|
||||
}
|
||||
if is_main {
|
||||
g.indent++
|
||||
g.profile_fn(it.name)
|
||||
}
|
||||
g.stmts(it.stmts)
|
||||
if is_main {
|
||||
g.indent--
|
||||
}
|
||||
// ////////////
|
||||
if is_main {
|
||||
if g.autofree {
|
||||
g.writeln('\t_vcleanup();')
|
||||
}
|
||||
if g.is_test {
|
||||
verror('test files cannot have function `main`')
|
||||
}
|
||||
}
|
||||
g.write_defer_stmts_when_needed()
|
||||
// /////////
|
||||
if g.autofree && !is_main {
|
||||
if g.autofree {
|
||||
// TODO: remove this, when g.write_autofree_stmts_when_needed works properly
|
||||
g.writeln(g.autofree_scope_vars(it.body_pos.pos))
|
||||
}
|
||||
if is_main {
|
||||
g.writeln('\treturn 0;')
|
||||
}
|
||||
g.writeln('}')
|
||||
g.defer_stmts = []
|
||||
if g.pref.printfn_list.len > 0 && g.last_fn_c_name in g.pref.printfn_list {
|
||||
@ -249,7 +183,7 @@ fn (mut g Gen) fn_args(args []table.Arg, is_variadic bool) ([]string, []string)
|
||||
caname := c_name(arg.name)
|
||||
typ := g.unwrap_generic(arg.typ)
|
||||
arg_type_sym := g.table.get_type_symbol(typ)
|
||||
mut arg_type_name := g.typ(typ) // arg_type_sym.name.replace('.', '__')
|
||||
mut arg_type_name := g.typ(typ) // util.no_dots(arg_type_sym.name)
|
||||
// if arg.name == 'xxx' {
|
||||
// println('xxx arg type= ' + arg_type_name)
|
||||
// }
|
||||
@ -356,7 +290,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
// mut receiver_type_name := g.cc_type(node.receiver_type)
|
||||
// mut receiver_type_name := g.typ(node.receiver_type)
|
||||
typ_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver_type))
|
||||
mut receiver_type_name := typ_sym.name.replace('.', '__')
|
||||
mut receiver_type_name := util.no_dots(typ_sym.name)
|
||||
if typ_sym.kind == .interface_ {
|
||||
// Speaker_name_table[s._interface_idx].speak(s._object)
|
||||
g.write('${c_name(receiver_type_name)}_name_table[')
|
||||
@ -413,7 +347,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
g.write('*($return_type_str*)')
|
||||
}
|
||||
}
|
||||
mut name := '${receiver_type_name}_$node.name'.replace('.', '__')
|
||||
mut name := util.no_dots('${receiver_type_name}_$node.name')
|
||||
// Check if expression is: arr[a..b].clone(), arr[a..].clone()
|
||||
// if so, then instead of calling array_clone(&array_slice(...))
|
||||
// call array_clone_static(array_slice(...))
|
||||
@ -424,7 +358,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||
if idx is ast.RangeExpr {
|
||||
// expr is arr[range].clone()
|
||||
// use array_clone_static instead of array_clone
|
||||
name = '${receiver_type_name}_${node.name}_static'.replace('.', '__')
|
||||
name = util.no_dots('${receiver_type_name}_${node.name}_static')
|
||||
is_range_slice = true
|
||||
}
|
||||
}
|
||||
@ -507,13 +441,13 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
if node.language == .c {
|
||||
// Skip "C."
|
||||
g.is_c_call = true
|
||||
name = name[2..].replace('.', '__')
|
||||
name = util.no_dots(name[2..])
|
||||
} else {
|
||||
name = c_name(name)
|
||||
}
|
||||
if is_json_encode {
|
||||
// `json__encode` => `json__encode_User`
|
||||
name += '_' + json_type_str.replace('.', '__')
|
||||
name += '_' + util.no_dots(json_type_str)
|
||||
}
|
||||
if node.generic_type != table.void_type && node.generic_type != 0 {
|
||||
// `foo<int>()` => `foo_int()`
|
||||
|
@ -1337,8 +1337,8 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
|
||||
fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
|
||||
// key_typ_sym := g.table.get_type_symbol(it.key_type)
|
||||
// value_typ_sym := g.table.get_type_symbol(it.value_type)
|
||||
// key_typ_str := key_typ_sym.name.replace('.', '__')
|
||||
// value_typ_str := value_typ_sym.name.replace('.', '__')
|
||||
// key_typ_str := util.no_dots(key_typ_sym.name)
|
||||
// value_typ_str := util.no_dots(value_typ_sym.name)
|
||||
if it.vals.len > 0 {
|
||||
g.writeln('new Map([')
|
||||
g.inc_indent()
|
||||
|
@ -4,6 +4,7 @@
|
||||
module gen
|
||||
|
||||
import v.table
|
||||
import v.util
|
||||
import strings
|
||||
|
||||
// TODO replace with comptime code generation.
|
||||
@ -128,12 +129,12 @@ $enc_fn_dec {
|
||||
|
||||
fn js_enc_name(typ string) string {
|
||||
name := 'json__encode_$typ'
|
||||
return name.replace('.', '__')
|
||||
return util.no_dots(name)
|
||||
}
|
||||
|
||||
fn js_dec_name(typ string) string {
|
||||
name := 'json__decode_$typ'
|
||||
return name.replace('.', '__')
|
||||
return util.no_dots(name)
|
||||
}
|
||||
|
||||
fn is_js_prim(typ string) bool {
|
||||
|
@ -6,15 +6,10 @@ pub struct ProfileCounterMeta{
|
||||
vpc_calls string
|
||||
}
|
||||
|
||||
fn (mut g Gen) profile_fn(fn_name string, is_main bool){
|
||||
if is_main {
|
||||
g.writeln('')
|
||||
g.writeln('\tatexit(vprint_profile_stats);')
|
||||
g.writeln('')
|
||||
}
|
||||
fn (mut g Gen) profile_fn(fn_name string){
|
||||
if g.pref.profile_no_inline && 'inline' in g.attrs {
|
||||
g.defer_profile_code = ''
|
||||
return
|
||||
return
|
||||
}
|
||||
if fn_name.starts_with('time.vpc_now') {
|
||||
g.defer_profile_code = ''
|
||||
@ -33,7 +28,7 @@ fn (mut g Gen) profile_fn(fn_name string, is_main bool){
|
||||
|
||||
pub fn (mut g Gen) gen_vprint_profile_stats() {
|
||||
g.pcs_declarations.writeln('void vprint_profile_stats(){')
|
||||
fstring := '"%14llu %14.3fms %14.0fns %s \\n"'
|
||||
fstring := '"%14lu %14.3fms %14.0fns %s \\n"'
|
||||
if g.pref.profile_file == '-' {
|
||||
for pc_meta in g.pcs {
|
||||
g.pcs_declarations.writeln('\tif (${pc_meta.vpc_calls}) printf($fstring, ${pc_meta.vpc_calls}, ${pc_meta.vpc_name}/1000000.0, ${pc_meta.vpc_name}/${pc_meta.vpc_calls}, "${pc_meta.fn_name}" );')
|
||||
|
@ -5,6 +5,7 @@ module gen
|
||||
import v.ast
|
||||
import strings
|
||||
import v.table
|
||||
import v.util
|
||||
|
||||
// pg,mysql etc
|
||||
const (
|
||||
@ -26,16 +27,16 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||
g.writeln(';')
|
||||
g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("')
|
||||
if node.kind == .insert {
|
||||
g.write('insert into `$node.table_name` (')
|
||||
g.write('INSERT INTO `${util.strip_mod_name(node.table_name)}` (')
|
||||
} else {
|
||||
g.write('update `$node.table_name` set ')
|
||||
g.write('UPDATE `${util.strip_mod_name(node.table_name)}` SET ')
|
||||
}
|
||||
if node.kind == .insert {
|
||||
for i, field in node.fields {
|
||||
if field.name == 'id' {
|
||||
continue
|
||||
}
|
||||
g.write(field.name)
|
||||
g.write('`${field.name}`')
|
||||
if i < node.fields.len - 1 {
|
||||
g.write(', ')
|
||||
}
|
||||
@ -59,7 +60,7 @@ fn (mut g Gen) sql_stmt(node ast.SqlStmt) {
|
||||
g.write(', ')
|
||||
}
|
||||
}
|
||||
g.write(' where ')
|
||||
g.write(' WHERE ')
|
||||
}
|
||||
if node.kind == .update {
|
||||
g.expr_to_sql(node.where_expr)
|
||||
@ -101,24 +102,24 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
|
||||
```
|
||||
*/
|
||||
cur_line := g.go_before_stmt(0)
|
||||
mut q := 'select '
|
||||
mut sql_query := 'SELECT '
|
||||
if node.is_count {
|
||||
// `select count(*) from User`
|
||||
q += 'count(*) from `$node.table_name`'
|
||||
sql_query += 'COUNT(*) FROM `${util.strip_mod_name(node.table_name)}` '
|
||||
} else {
|
||||
// `select id, name, country from User`
|
||||
for i, field in node.fields {
|
||||
q += '$field.name'
|
||||
sql_query += '`${field.name}`'
|
||||
if i < node.fields.len - 1 {
|
||||
q += ', '
|
||||
sql_query += ', '
|
||||
}
|
||||
}
|
||||
q += ' from `$node.table_name`'
|
||||
sql_query += ' FROM `${util.strip_mod_name(node.table_name)}`'
|
||||
}
|
||||
if node.has_where {
|
||||
q += ' where '
|
||||
sql_query += ' WHERE '
|
||||
}
|
||||
// g.write('${dbtype}__DB_q_int(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q')
|
||||
// g.write('${dbtype}__DB_q_int(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$sql_query')
|
||||
g.sql_stmt_name = g.new_tmp_var()
|
||||
db_name := g.new_tmp_var()
|
||||
g.writeln('\n\t// sql select')
|
||||
@ -126,18 +127,19 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) {
|
||||
g.write('${dbtype}__DB $db_name = ') // $node.db_var_name;')
|
||||
g.expr(node.db_expr)
|
||||
g.writeln(';')
|
||||
// g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q')
|
||||
g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("$q')
|
||||
// g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$sql_query')
|
||||
g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("')
|
||||
g.write(sql_query)
|
||||
if node.has_where && node.where_expr is ast.InfixExpr {
|
||||
g.expr_to_sql(node.where_expr)
|
||||
}
|
||||
g.write(' order by id ')
|
||||
g.write(' ORDER BY id ')
|
||||
if node.has_limit {
|
||||
g.write(' limit ')
|
||||
g.write(' LIMIT ')
|
||||
g.expr_to_sql(node.limit_expr)
|
||||
}
|
||||
if node.has_offset {
|
||||
g.write(' offset ')
|
||||
g.write(' OFFSET ')
|
||||
g.expr_to_sql(node.offset_expr)
|
||||
}
|
||||
g.writeln('"));')
|
||||
|
@ -799,7 +799,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
||||
fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
println(term.green('\n$node.name:'))
|
||||
g.stack_var_pos = 0
|
||||
is_main := node.name == 'main'
|
||||
is_main := node.name == 'main.main'
|
||||
// println('saving addr $node.name $g.buf.len.hex2()')
|
||||
if is_main {
|
||||
g.save_main_fn_addr()
|
||||
|
@ -121,7 +121,7 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
|
||||
for stmt in file.stmts {
|
||||
if stmt is ast.FnDecl {
|
||||
fn_decl := stmt as ast.FnDecl
|
||||
if fn_decl.name == 'vweb_tmpl_$p.cur_fn_name' {
|
||||
if fn_decl.name == 'main.vweb_tmpl_${p.cur_fn_name}' {
|
||||
tmpl_scope := file.scope.innermost(fn_decl.body_pos.pos)
|
||||
for _, obj in p.scope.objects {
|
||||
if obj is ast.Var {
|
||||
|
@ -35,7 +35,8 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
||||
// In case of `foo<T>()`
|
||||
// T is unwrapped and registered in the checker.
|
||||
if !generic_type.has_flag(.generic) {
|
||||
p.table.register_fn_gen_type(fn_name, generic_type)
|
||||
full_generic_fn_name := if fn_name.contains('.') { fn_name } else { p.prepend_mod(fn_name) }
|
||||
p.table.register_fn_gen_type(full_generic_fn_name, generic_type)
|
||||
}
|
||||
}
|
||||
p.check(.lpar)
|
||||
@ -227,7 +228,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
// Register
|
||||
if is_method {
|
||||
mut type_sym := p.table.get_type_symbol(rec_type)
|
||||
// p.warn('reg method $type_sym.name . $name ()')
|
||||
// p.warn('reg method $type_sym.name . $name ()')
|
||||
type_sym.register_method(table.Fn{
|
||||
name: name
|
||||
args: args
|
||||
@ -237,6 +238,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
is_pub: is_pub
|
||||
is_deprecated: is_deprecated
|
||||
ctdefine: ctdefine
|
||||
mod: p.mod
|
||||
})
|
||||
} else {
|
||||
if language == .c {
|
||||
@ -249,6 +251,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
if _ := p.table.find_fn(name) {
|
||||
p.fn_redefinition_error(name)
|
||||
}
|
||||
//p.warn('reg functn $name ()')
|
||||
p.table.register_fn(table.Fn{
|
||||
name: name
|
||||
args: args
|
||||
@ -372,7 +375,8 @@ fn (mut p Parser) fn_args() ([]table.Arg, bool, bool) {
|
||||
mut args := []table.Arg{}
|
||||
mut is_variadic := false
|
||||
// `int, int, string` (no names, just types)
|
||||
types_only := p.tok.kind in [.amp, .ellipsis, .key_fn] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) ||
|
||||
argname := if p.tok.kind == .name && p.tok.lit.len > 0 && p.tok.lit[0].is_capital() { p.prepend_mod(p.tok.lit) } else { p.tok.lit }
|
||||
types_only := p.tok.kind in [.amp, .ellipsis, .key_fn] || (p.peek_tok.kind == .comma && p.table.known_type(argname)) ||
|
||||
p.peek_tok.kind == .rpar
|
||||
// TODO copy pasta, merge 2 branches
|
||||
if types_only {
|
||||
@ -500,16 +504,13 @@ fn (mut p Parser) fn_redefinition_error(name string) {
|
||||
}
|
||||
|
||||
fn have_fn_main(stmts []ast.Stmt) bool {
|
||||
mut has_main_fn := false
|
||||
for stmt in stmts {
|
||||
match stmt {
|
||||
ast.FnDecl {
|
||||
if stmt.name == 'main' {
|
||||
has_main_fn = true
|
||||
}
|
||||
if stmt is ast.FnDecl {
|
||||
f := stmt as ast.FnDecl
|
||||
if f.name == 'main.main' && f.mod == 'main' {
|
||||
return true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
return has_main_fn
|
||||
return false
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ fn (p &Parser) prepend_mod(name string) string {
|
||||
if p.expr_mod != '' {
|
||||
return p.expr_mod + '.' + name
|
||||
}
|
||||
if p.builtin_mod || p.mod == 'main' {
|
||||
if p.builtin_mod {
|
||||
return name
|
||||
}
|
||||
return '${p.mod}.$name'
|
||||
|
@ -167,7 +167,7 @@ pub fn (mut p Parser) parse_any_type(language table.Language, is_ptr bool) table
|
||||
name = '${p.imports[name]}.$p.tok.lit'
|
||||
} else if p.expr_mod != '' {
|
||||
name = p.expr_mod + '.' + name
|
||||
} else if p.mod !in ['builtin', 'main'] && name !in table.builtin_type_names && name.len > 1 {
|
||||
} else if p.mod !in ['builtin'] && name !in p.table.type_idxs && name.len > 1 {
|
||||
// `Foo` in module `mod` means `mod.Foo`
|
||||
name = p.mod + '.' + name
|
||||
}
|
||||
|
@ -148,16 +148,7 @@ fn (mut p Parser) parse() ast.File {
|
||||
}
|
||||
for {
|
||||
if p.tok.kind == .eof {
|
||||
if p.pref.is_script && !p.pref.is_test && p.mod == 'main' && !have_fn_main(stmts) {
|
||||
stmts << ast.FnDecl{
|
||||
name: 'main'
|
||||
mod: p.mod
|
||||
file: p.file_name
|
||||
return_type: table.void_type
|
||||
}
|
||||
} else {
|
||||
p.check_unused_imports()
|
||||
}
|
||||
p.check_unused_imports()
|
||||
break
|
||||
}
|
||||
// println('stmt at ' + p.tok.str())
|
||||
@ -449,8 +440,8 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
|
||||
stmts << p.stmt(false)
|
||||
}
|
||||
return ast.FnDecl{
|
||||
name: 'main'
|
||||
mod: p.mod
|
||||
name: 'main.main'
|
||||
mod: 'main'
|
||||
stmts: stmts
|
||||
file: p.file_name
|
||||
return_type: table.void_type
|
||||
@ -845,19 +836,11 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||
if p.tok.lit in ['r', 'c', 'js'] && p.peek_tok.kind == .string && !p.inside_str_interp {
|
||||
return p.string_expr()
|
||||
}
|
||||
mut known_var := false
|
||||
if obj := p.scope.find(p.tok.lit) {
|
||||
match mut obj {
|
||||
ast.Var {
|
||||
known_var = true
|
||||
obj.is_used = true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
known_var := p.mark_var_as_used( p.tok.lit )
|
||||
mut is_mod_cast := false
|
||||
if p.peek_tok.kind == .dot && !known_var &&
|
||||
(language != .v || p.known_import(p.tok.lit) || p.mod.all_after_last('.') == p.tok.lit) {
|
||||
(language != .v || p.known_import(p.tok.lit) ||
|
||||
p.mod.all_after_last('.') == p.tok.lit) {
|
||||
if language == .c {
|
||||
mod = 'C'
|
||||
} else if language == .js {
|
||||
@ -1490,10 +1473,10 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
||||
pubfn := if p.mod == 'main' { 'fn' } else { 'pub fn' }
|
||||
p.scanner.codegen('
|
||||
//
|
||||
$pubfn ( e &$name) has(flag $name) bool { return (int(*e) & (1 << int(flag))) != 0 }
|
||||
$pubfn (mut e $name) set(flag $name) { unsafe{ *e = int(*e) | (1 << int(flag)) } }
|
||||
$pubfn (mut e $name) clear(flag $name) { unsafe{ *e = int(*e) & ~(1 << int(flag)) } }
|
||||
$pubfn (mut e $name) toggle(flag $name) { unsafe{ *e = int(*e) ^ (1 << int(flag)) } }
|
||||
$pubfn ( e &$enum_name) has(flag $enum_name) bool { return (int(*e) & (1 << int(flag))) != 0 }
|
||||
$pubfn (mut e $enum_name) set(flag $enum_name) { unsafe{ *e = int(*e) | (1 << int(flag)) } }
|
||||
$pubfn (mut e $enum_name) clear(flag $enum_name) { unsafe{ *e = int(*e) & ~(1 << int(flag)) } }
|
||||
$pubfn (mut e $enum_name) toggle(flag $enum_name) { unsafe{ *e = int(*e) ^ (1 << int(flag)) } }
|
||||
//
|
||||
')
|
||||
}
|
||||
@ -1687,3 +1670,16 @@ fn (mut p Parser) rewind_scanner_to_current_token_in_new_mode() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) mark_var_as_used(varname string) bool {
|
||||
if obj := p.scope.find(varname) {
|
||||
match mut obj {
|
||||
ast.Var {
|
||||
obj.is_used = true
|
||||
return true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -94,19 +94,24 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||
}
|
||||
}
|
||||
.key_sizeof {
|
||||
pos := p.tok.position()
|
||||
p.next() // sizeof
|
||||
p.check(.lpar)
|
||||
sizeof_type := p.parse_type()
|
||||
if p.tok.lit == 'C' {
|
||||
p.next()
|
||||
p.check(.dot)
|
||||
is_known_var := p.mark_var_as_used( p.tok.lit )
|
||||
if is_known_var {
|
||||
expr := p.parse_ident(table.Language.v)
|
||||
node = ast.SizeOf{
|
||||
type_name: p.check_name()
|
||||
typ: sizeof_type
|
||||
is_type: false
|
||||
expr: expr
|
||||
pos: pos
|
||||
}
|
||||
} else {
|
||||
sizeof_type := p.parse_type()
|
||||
node = ast.SizeOf{
|
||||
is_type: true
|
||||
typ: sizeof_type
|
||||
type_name: p.table.get_type_symbol(sizeof_type).name
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
p.check(.rpar)
|
||||
|
@ -151,7 +151,7 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
||||
} else if kind == .update {
|
||||
if !p.pref.is_fmt {
|
||||
// NB: in vfmt mode, v parses just a single file and table_name may not have been registered
|
||||
idx := p.table.find_type_idx(table_name)
|
||||
idx := p.table.find_type_idx(p.prepend_mod(table_name))
|
||||
table_type = table.new_type(idx)
|
||||
}
|
||||
p.check_sql_keyword('where')
|
||||
|
93
vlib/v/scanner/scanner_at_literals_test.v
Normal file
93
vlib/v/scanner/scanner_at_literals_test.v
Normal file
@ -0,0 +1,93 @@
|
||||
module scanner
|
||||
|
||||
import os
|
||||
|
||||
struct TestStruct {
|
||||
test string
|
||||
}
|
||||
|
||||
fn (mut t TestStruct) test_struct() {
|
||||
assert @STRUCT == 'TestStruct'
|
||||
}
|
||||
|
||||
fn (mut t TestStruct) test_struct_w_return() string {
|
||||
assert @STRUCT == 'TestStruct'
|
||||
return t.test
|
||||
}
|
||||
|
||||
fn (mut t TestStruct) test_struct_w_high_order(cb fn(int)string) string {
|
||||
assert @STRUCT == 'TestStruct'
|
||||
return 'test'+cb(2)
|
||||
}
|
||||
|
||||
struct TestFn { }
|
||||
|
||||
fn (mut t TestFn) tst_1() {
|
||||
assert @FN == 'tst_1'
|
||||
}
|
||||
|
||||
fn (mut t TestFn) tst_2(cb fn(int)) {
|
||||
assert @FN == 'tst_2'
|
||||
cb(1)
|
||||
}
|
||||
|
||||
fn fn_name_mod_level() {
|
||||
assert @FN == 'fn_name_mod_level'
|
||||
}
|
||||
|
||||
fn fn_name_mod_level_high_order(cb fn(int)) {
|
||||
assert @FN == 'fn_name_mod_level_high_order'
|
||||
cb(1)
|
||||
}
|
||||
|
||||
fn test_at_file() {
|
||||
// Test @FILE
|
||||
f := os.file_name( @FILE )
|
||||
assert f == 'scanner_at_literals_test.v'
|
||||
}
|
||||
|
||||
fn test_at_fn() {
|
||||
// Test @FN
|
||||
assert @FN == 'test_at_fn'
|
||||
|
||||
fn_name_mod_level()
|
||||
fn_name_mod_level_high_order(fn(i int){
|
||||
t := i + 1
|
||||
assert t == 2
|
||||
})
|
||||
|
||||
mut tfn := TestFn{}
|
||||
tfn.tst_1()
|
||||
tfn.tst_2(fn(i int){
|
||||
t := i + 1
|
||||
assert t == 2
|
||||
})
|
||||
}
|
||||
|
||||
fn test_at_mod() {
|
||||
// Test @MOD
|
||||
assert @MOD == 'scanner'
|
||||
}
|
||||
|
||||
fn test_at_struct() {
|
||||
// Test @STRUCT
|
||||
assert @STRUCT == ''
|
||||
mut ts := TestStruct { test: "test" }
|
||||
ts.test_struct()
|
||||
r1 := ts.test_struct_w_return()
|
||||
r2 := ts.test_struct_w_high_order(fn(i int)string{
|
||||
assert @STRUCT == ''
|
||||
return i.str()
|
||||
})
|
||||
assert r1 == 'test'
|
||||
assert r2 == 'test2'
|
||||
}
|
||||
|
||||
fn test_vmod_file() {
|
||||
content := @VMOD_FILE
|
||||
assert content.len > 0
|
||||
assert content.contains('Module {')
|
||||
assert content.contains('name:')
|
||||
assert content.contains('version:')
|
||||
assert content.contains('description:')
|
||||
}
|
@ -5,45 +5,6 @@ module scanner
|
||||
|
||||
import v.token
|
||||
|
||||
|
||||
struct TestStruct {
|
||||
test string
|
||||
}
|
||||
|
||||
fn (mut t TestStruct) test_struct() {
|
||||
assert @STRUCT == 'TestStruct'
|
||||
}
|
||||
|
||||
fn (mut t TestStruct) test_struct_w_return() string {
|
||||
assert @STRUCT == 'TestStruct'
|
||||
return t.test
|
||||
}
|
||||
|
||||
fn (mut t TestStruct) test_struct_w_high_order(cb fn(int)string) string {
|
||||
assert @STRUCT == 'TestStruct'
|
||||
return 'test'+cb(2)
|
||||
}
|
||||
|
||||
struct TestFn { }
|
||||
|
||||
fn (mut t TestFn) tst_1() {
|
||||
assert @FN == 'tst_1'
|
||||
}
|
||||
|
||||
fn (mut t TestFn) tst_2(cb fn(int)) {
|
||||
assert @FN == 'tst_2'
|
||||
cb(1)
|
||||
}
|
||||
|
||||
fn fn_name_mod_level() {
|
||||
assert @FN == 'fn_name_mod_level'
|
||||
}
|
||||
|
||||
fn fn_name_mod_level_high_order(cb fn(int)) {
|
||||
assert @FN == 'fn_name_mod_level_high_order'
|
||||
cb(1)
|
||||
}
|
||||
|
||||
fn scan_kinds(text string) []token.Kind {
|
||||
mut scanner := new_scanner(text, .skip_comments, false)
|
||||
mut token_kinds := []token.Kind{}
|
||||
@ -66,14 +27,18 @@ fn test_scan() {
|
||||
assert token_kinds[3] == .plus
|
||||
assert token_kinds[4] == .number
|
||||
assert token_kinds[5] == .rpar
|
||||
// test number costants input format
|
||||
}
|
||||
|
||||
fn test_number_constant_input_format() {
|
||||
mut c := 0xa0
|
||||
assert c == 0xa0
|
||||
c = 0b1001
|
||||
assert c == 9
|
||||
c = 1000000
|
||||
assert c == 1000000
|
||||
// test float conversion and reading
|
||||
}
|
||||
|
||||
fn test_float_conversion_and_reading() {
|
||||
d := 23000000e-3
|
||||
assert int(d) == 23000
|
||||
mut e := 1.2E3 * -1e-1
|
||||
@ -83,92 +48,62 @@ fn test_scan() {
|
||||
assert 1.23e+10 == 1.23e10
|
||||
assert 1.23e+10 == 1.23e0010
|
||||
assert (-1.23e+10) == (1.23e0010 * -1.0)
|
||||
|
||||
// Test @FN
|
||||
assert @FN == 'test_scan'
|
||||
|
||||
fn_name_mod_level()
|
||||
fn_name_mod_level_high_order(fn(i int){
|
||||
t := i + 1
|
||||
assert t == 2
|
||||
})
|
||||
|
||||
mut tfn := TestFn{}
|
||||
tfn.tst_1()
|
||||
tfn.tst_2(fn(i int){
|
||||
t := i + 1
|
||||
assert t == 2
|
||||
})
|
||||
|
||||
// Test @MOD
|
||||
assert @MOD == 'scanner'
|
||||
|
||||
// Test @STRUCT
|
||||
assert @STRUCT == ''
|
||||
|
||||
mut ts := TestStruct { test: "test" }
|
||||
ts.test_struct()
|
||||
r1 := ts.test_struct_w_return()
|
||||
r2 := ts.test_struct_w_high_order(fn(i int)string{
|
||||
assert @STRUCT == ''
|
||||
return i.str()
|
||||
})
|
||||
assert r1 == 'test'
|
||||
assert r2 == 'test2'
|
||||
|
||||
}
|
||||
|
||||
fn test_vmod_file() {
|
||||
content := @VMOD_FILE
|
||||
assert content.len > 0
|
||||
assert content.contains('Module {')
|
||||
assert content.contains('name:')
|
||||
assert content.contains('version:')
|
||||
assert content.contains('description:')
|
||||
}
|
||||
|
||||
fn test_reference() {
|
||||
mut result := scan_kinds('true && false')
|
||||
fn test_reference_bools() {
|
||||
result := scan_kinds('true && false')
|
||||
assert result.len == 3
|
||||
assert result[0] == .key_true
|
||||
assert result[1] == .and
|
||||
assert result[2] == .key_false
|
||||
}
|
||||
|
||||
result = scan_kinds('&foo')
|
||||
fn test_reference_var() {
|
||||
result := scan_kinds('&foo')
|
||||
assert result.len == 2
|
||||
assert result[0] == .amp
|
||||
assert result[1] == .name
|
||||
}
|
||||
|
||||
result = scan_kinds('[]&foo')
|
||||
fn test_array_of_references() {
|
||||
result := scan_kinds('[]&foo')
|
||||
assert result.len == 4
|
||||
assert result[0] == .lsbr
|
||||
assert result[1] == .rsbr
|
||||
assert result[2] == .amp
|
||||
assert result[3] == .name
|
||||
}
|
||||
|
||||
result = scan_kinds('&[]&foo')
|
||||
fn test_ref_array_of_references() {
|
||||
result := scan_kinds('&[]&foo')
|
||||
assert result.len == 5
|
||||
assert result[0] == .amp
|
||||
assert result[1] == .lsbr
|
||||
assert result[2] == .rsbr
|
||||
assert result[3] == .amp
|
||||
assert result[4] == .name
|
||||
}
|
||||
|
||||
result = scan_kinds('&&foo')
|
||||
fn test_ref_ref_foo() {
|
||||
result := scan_kinds('&&foo')
|
||||
assert result.len == 3
|
||||
assert result[0] == .amp
|
||||
assert result[1] == .amp
|
||||
assert result[2] == .name
|
||||
}
|
||||
|
||||
result = scan_kinds('[]&&foo')
|
||||
fn test_array_of_ref_ref_foo() {
|
||||
result := scan_kinds('[]&&foo')
|
||||
assert result.len == 5
|
||||
assert result[0] == .lsbr
|
||||
assert result[1] == .rsbr
|
||||
assert result[2] == .amp
|
||||
assert result[3] == .amp
|
||||
assert result[4] == .name
|
||||
}
|
||||
|
||||
result = scan_kinds('&&[]&&foo')
|
||||
fn test_ref_ref_array_ref_ref_foo() {
|
||||
result := scan_kinds('&&[]&&foo')
|
||||
assert result.len == 7
|
||||
assert result[0] == .amp
|
||||
assert result[1] == .amp
|
||||
|
@ -108,11 +108,12 @@ pub fn (t &Table) known_fn(name string) bool {
|
||||
}
|
||||
|
||||
pub fn (mut t Table) register_fn(new_fn Fn) {
|
||||
// println('reg fn $new_fn.name nr_args=$new_fn.args.len')
|
||||
// println('reg fn $new_fn.name nr_args=$new_fn.args.len')
|
||||
t.fns[new_fn.name] = new_fn
|
||||
}
|
||||
|
||||
pub fn (mut t TypeSymbol) register_method(new_fn Fn) {
|
||||
// println('reg me $new_fn.name nr_args=$new_fn.args.len')
|
||||
t.methods << new_fn
|
||||
}
|
||||
|
||||
|
25
vlib/v/tests/project_with_tests_for_main/README.md
Normal file
25
vlib/v/tests/project_with_tests_for_main/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
This folder contains a V project,
|
||||
intended to be used as a demonstration
|
||||
for how to test functions defined inside
|
||||
a main module.
|
||||
|
||||
See my_test.v and my_other_test.v .
|
||||
These files work as any other internal module tests,
|
||||
i.e. they do `module main` at their top, so that v knows,
|
||||
that they are internal tests, and for which module they apply.
|
||||
|
||||
When you do `v my_test.v`, v will try to find other *.v files in
|
||||
the same folder that also have `module main` at their top,
|
||||
then it will process them and process the my_test.v file too.
|
||||
|
||||
The v `fn main(){}` function that you most likely also have will get
|
||||
compiled as normal to `void main__main(){...}`, but it will NOT be
|
||||
called by anything, so it will not mess up your tests.
|
||||
|
||||
Instead, your test_ functions will get called inside the generated
|
||||
`int main(){...}` test runner, just like it is the case with all _test.v
|
||||
files (internal or external ones).
|
||||
|
||||
NB: each _test.v file is compiled separately from all other _test.v
|
||||
files, so you can have conflicting test_ functions in them without a
|
||||
problem too.
|
9
vlib/v/tests/project_with_tests_for_main/main.v
Normal file
9
vlib/v/tests/project_with_tests_for_main/main.v
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
fn iadd(x int, y int) int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
fn main(){
|
||||
println('Hello world')
|
||||
println('iadd: ' + iadd(1,2).str())
|
||||
}
|
6
vlib/v/tests/project_with_tests_for_main/my_other_test.v
Normal file
6
vlib/v/tests/project_with_tests_for_main/my_other_test.v
Normal file
@ -0,0 +1,6 @@
|
||||
module main
|
||||
fn test_iadd_3_4(){
|
||||
a := iadd(3,4)
|
||||
assert a == 7
|
||||
assert iadd(10,20) == 30
|
||||
}
|
9
vlib/v/tests/project_with_tests_for_main/my_test.v
Normal file
9
vlib/v/tests/project_with_tests_for_main/my_test.v
Normal file
@ -0,0 +1,9 @@
|
||||
module main
|
||||
fn test_iadd_3_4(){
|
||||
a := iadd(3,4)
|
||||
assert a == 7
|
||||
}
|
||||
fn test_iadd_5_6(){
|
||||
a := iadd(5,6)
|
||||
assert a == 11
|
||||
}
|
5
vlib/v/tests/project_with_tests_for_main/v.mod
Normal file
5
vlib/v/tests/project_with_tests_for_main/v.mod
Normal file
@ -0,0 +1,5 @@
|
||||
Module {
|
||||
name: 'project_with_tests_for_main',
|
||||
description: 'This project demonstrates the ability to test functions in the main module',
|
||||
dependencies: []
|
||||
}
|
@ -63,7 +63,8 @@ fn color(kind, msg string) string {
|
||||
}
|
||||
|
||||
// formatted_error - `kind` may be 'error' or 'warn'
|
||||
pub fn formatted_error(kind, emsg, filepath string, pos token.Position) string {
|
||||
pub fn formatted_error(kind, omsg, filepath string, pos token.Position) string {
|
||||
emsg := omsg.replace('main.', '')
|
||||
mut path := filepath
|
||||
verror_paths_override := os.getenv('VERROR_PATHS')
|
||||
if verror_paths_override == 'absolute' {
|
||||
|
@ -331,3 +331,15 @@ pub fn ensure_modules_for_all_tools_are_installed(is_verbose bool) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn strip_mod_name(name string) string {
|
||||
return name.all_after_last('.')
|
||||
}
|
||||
|
||||
pub fn strip_main_name(name string) string {
|
||||
return name.replace('main.','')
|
||||
}
|
||||
|
||||
pub fn no_dots(s string) string {
|
||||
return s.replace('.', '__')
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user