run vfmt
parent
b6fe2ebc0b
commit
6210984c97
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -9,20 +8,19 @@ import (
|
||||||
benchmark
|
benchmark
|
||||||
os
|
os
|
||||||
filepath
|
filepath
|
||||||
//time
|
// time
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
known_commands = ['run', 'build', 'version', 'doc']
|
known_commands = ['run', 'build', 'version', 'doc']
|
||||||
simple_tools = ['up', 'create', 'test', 'test-compiler', 'build-tools',
|
simple_tools = ['up', 'create', 'test', 'test-compiler', 'build-tools', 'build-examples', 'build-vbinaries']
|
||||||
'build-examples', 'build-vbinaries']
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
//t := time.ticks()
|
// t := time.ticks()
|
||||||
//defer { println(time.ticks() - t) }
|
// defer { println(time.ticks() - t) }
|
||||||
args := compiler.env_vflags_and_os_args()
|
args := compiler.env_vflags_and_os_args()
|
||||||
options, command := compiler.get_v_options_and_main_command( args )
|
options,command := compiler.get_v_options_and_main_command(args)
|
||||||
// external tool
|
// external tool
|
||||||
if command in simple_tools {
|
if command in simple_tools {
|
||||||
compiler.launch_tool('v' + command)
|
compiler.launch_tool('v' + command)
|
||||||
|
@ -61,7 +59,8 @@ fn main() {
|
||||||
mut tmark := benchmark.new_benchmark()
|
mut tmark := benchmark.new_benchmark()
|
||||||
if v.pref.x64 {
|
if v.pref.x64 {
|
||||||
v.compile_x64()
|
v.compile_x64()
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
v.compile()
|
v.compile()
|
||||||
}
|
}
|
||||||
if v.pref.is_stats {
|
if v.pref.is_stats {
|
||||||
|
@ -76,7 +75,8 @@ fn main() {
|
||||||
|
|
||||||
fn v_command(command string, args []string) {
|
fn v_command(command string, args []string) {
|
||||||
match command {
|
match command {
|
||||||
'', '.', 'run', 'build' { // handled later in vlib/compiler/main.v
|
'', '.', 'run', 'build' {
|
||||||
|
// handled later in vlib/compiler/main.v
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
'version' {
|
'version' {
|
||||||
|
@ -109,7 +109,7 @@ fn v_command(command string, args []string) {
|
||||||
os.chdir(vdir)
|
os.chdir(vdir)
|
||||||
mod := args.last()
|
mod := args.last()
|
||||||
os.system('$vexe build module vlib$os.path_separator' + args.last())
|
os.system('$vexe build module vlib$os.path_separator' + args.last())
|
||||||
txt := os.read_file(filepath.join(compiler.v_modules_path, 'vlib', '${mod}.vh')) or {
|
txt := os.read_file(filepath.join(compiler.v_modules_path,'vlib','${mod}.vh'))or{
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
println(txt)
|
println(txt)
|
||||||
|
@ -118,8 +118,7 @@ fn v_command(command string, args []string) {
|
||||||
else {
|
else {
|
||||||
println('v $command: unknown command')
|
println('v $command: unknown command')
|
||||||
println('Run "v help" for usage.')
|
println('Run "v help" for usage.')
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ module benchmark
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import term
|
import term
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Example usage of this module:
|
Example usage of this module:
|
||||||
```
|
```
|
||||||
|
@ -26,19 +25,20 @@ println( bmark.total_message('remarks about the benchmark') )
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub struct Benchmark{
|
|
||||||
|
pub struct Benchmark {
|
||||||
pub mut:
|
pub mut:
|
||||||
bench_start_time i64
|
bench_start_time i64
|
||||||
bench_end_time i64
|
bench_end_time i64
|
||||||
step_start_time i64
|
step_start_time i64
|
||||||
step_end_time i64
|
step_end_time i64
|
||||||
ntotal int
|
ntotal int
|
||||||
nok int
|
nok int
|
||||||
nfail int
|
nfail int
|
||||||
verbose bool
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_benchmark() Benchmark{
|
pub fn new_benchmark() Benchmark {
|
||||||
return Benchmark{
|
return Benchmark{
|
||||||
bench_start_time: benchmark.now()
|
bench_start_time: benchmark.now()
|
||||||
verbose: true
|
verbose: true
|
||||||
|
@ -67,14 +67,14 @@ pub fn (b mut Benchmark) ok() {
|
||||||
|
|
||||||
pub fn (b mut Benchmark) fail_many(n int) {
|
pub fn (b mut Benchmark) fail_many(n int) {
|
||||||
b.step_end_time = benchmark.now()
|
b.step_end_time = benchmark.now()
|
||||||
b.ntotal+=n
|
b.ntotal += n
|
||||||
b.nfail+=n
|
b.nfail += n
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b mut Benchmark) ok_many(n int) {
|
pub fn (b mut Benchmark) ok_many(n int) {
|
||||||
b.step_end_time = benchmark.now()
|
b.step_end_time = benchmark.now()
|
||||||
b.ntotal+=n
|
b.ntotal += n
|
||||||
b.nok+=n
|
b.nok += n
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b mut Benchmark) neither_fail_nor_ok() {
|
pub fn (b mut Benchmark) neither_fail_nor_ok() {
|
||||||
|
@ -86,10 +86,7 @@ pub fn (b &Benchmark) step_message(msg string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b &Benchmark) total_message(msg string) string {
|
pub fn (b &Benchmark) total_message(msg string) string {
|
||||||
mut tmsg := '$msg \n ok, fail, total = ' +
|
mut tmsg := '$msg \n ok, fail, total = ' + term.ok_message('${b.nok:5d}') + ', ' + if b.nfail > 0 { term.fail_message('${b.nfail:5d}') } else { '${b.nfail:5d}' } + ', ' + '${b.ntotal:5d}'
|
||||||
term.ok_message('${b.nok:5d}') + ', ' +
|
|
||||||
if b.nfail > 0 { term.fail_message('${b.nfail:5d}') } else { '${b.nfail:5d}' } + ', ' +
|
|
||||||
'${b.ntotal:5d}'
|
|
||||||
if b.verbose {
|
if b.verbose {
|
||||||
tmsg = '<=== total time spent $tmsg'
|
tmsg = '<=== total time spent $tmsg'
|
||||||
}
|
}
|
||||||
|
@ -99,8 +96,8 @@ pub fn (b &Benchmark) total_message(msg string) string {
|
||||||
pub fn (b &Benchmark) total_duration() i64 {
|
pub fn (b &Benchmark) total_duration() i64 {
|
||||||
return (b.bench_end_time - b.bench_start_time)
|
return (b.bench_end_time - b.bench_start_time)
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
fn (b &Benchmark) tdiff_in_ms(s string, sticks i64, eticks i64) string {
|
fn (b &Benchmark) tdiff_in_ms(s string, sticks i64, eticks i64) string {
|
||||||
if b.verbose {
|
if b.verbose {
|
||||||
tdiff := (eticks - sticks)
|
tdiff := (eticks - sticks)
|
||||||
|
@ -112,3 +109,4 @@ fn (b &Benchmark) tdiff_in_ms(s string, sticks i64, eticks i64) string {
|
||||||
fn now() i64 {
|
fn now() i64 {
|
||||||
return time.ticks()
|
return time.ticks()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
fn (p mut Parser) inline_asm() {
|
fn (p mut Parser) inline_asm() {
|
||||||
if !p.inside_unsafe {
|
if !p.inside_unsafe {
|
||||||
p.error('asm() needs to be run inside `unsafe {}`')
|
p.error('asm() needs to be run inside `unsafe {}`')
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
s := p.check_string()
|
s := p.check_string()
|
||||||
|
@ -15,7 +14,7 @@ fn (p mut Parser) inline_asm() {
|
||||||
for p.tok == .str {
|
for p.tok == .str {
|
||||||
p.genln('"$p.lit"')
|
p.genln('"$p.lit"')
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
for p.tok == .colon {
|
for p.tok == .colon {
|
||||||
p.next()
|
p.next()
|
||||||
arg := p.check_string()
|
arg := p.check_string()
|
||||||
|
@ -25,11 +24,12 @@ fn (p mut Parser) inline_asm() {
|
||||||
var_name := p.check_name()
|
var_name := p.check_name()
|
||||||
if !p.known_var(var_name) {
|
if !p.known_var(var_name) {
|
||||||
p.error('unknown variable `$var_name`')
|
p.error('unknown variable `$var_name`')
|
||||||
}
|
}
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
p.genln('($var_name)')
|
p.genln('($var_name)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.genln(');')
|
p.genln(');')
|
||||||
p.check(.rcbr)
|
p.check(.rcbr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
// parsed cflag
|
// parsed cflag
|
||||||
struct CFlag{
|
struct CFlag {
|
||||||
mod string // the module in which the flag was given
|
mod string // the module in which the flag was given
|
||||||
os string // eg. windows | darwin | linux
|
os string // eg. windows | darwin | linux
|
||||||
name string // eg. -I
|
name string // eg. -I
|
||||||
|
@ -22,11 +20,7 @@ pub fn (c &CFlag) str() string {
|
||||||
fn (v &V) get_os_cflags() []CFlag {
|
fn (v &V) get_os_cflags() []CFlag {
|
||||||
mut flags := []CFlag
|
mut flags := []CFlag
|
||||||
for flag in v.table.cflags {
|
for flag in v.table.cflags {
|
||||||
if flag.os == ''
|
if flag.os == '' || (flag.os == 'linux' && v.os == .linux) || (flag.os == 'darwin' && v.os == .mac) || (flag.os == 'freebsd' && v.os == .freebsd) || (flag.os == 'windows' && v.os == .windows) {
|
||||||
|| (flag.os == 'linux' && v.os == .linux)
|
|
||||||
|| (flag.os == 'darwin' && v.os == .mac)
|
|
||||||
|| (flag.os == 'freebsd' && v.os == .freebsd)
|
|
||||||
|| (flag.os == 'windows' && v.os == .windows) {
|
|
||||||
flags << flag
|
flags << flag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +32,9 @@ fn (v &V) get_rest_of_module_cflags(c &CFlag) []CFlag {
|
||||||
cflags := v.get_os_cflags()
|
cflags := v.get_os_cflags()
|
||||||
for flag in cflags {
|
for flag in cflags {
|
||||||
if c.mod == flag.mod {
|
if c.mod == flag.mod {
|
||||||
if c.name == flag.name && c.value == flag.value && c.os == flag.os { continue }
|
if c.name == flag.name && c.value == flag.value && c.os == flag.os {
|
||||||
|
continue
|
||||||
|
}
|
||||||
flags << flag
|
flags << flag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,12 +44,12 @@ fn (v &V) get_rest_of_module_cflags(c &CFlag) []CFlag {
|
||||||
// format flag
|
// format flag
|
||||||
fn (cf &CFlag) format() string {
|
fn (cf &CFlag) format() string {
|
||||||
mut value := cf.value
|
mut value := cf.value
|
||||||
if cf.name in ['-l', '-Wa', '-Wl', '-Wp'] && value.len>0 {
|
if cf.name in ['-l', '-Wa', '-Wl', '-Wp'] && value.len > 0 {
|
||||||
return '${cf.name}${value}'.trim_space()
|
return '${cf.name}${value}'.trim_space()
|
||||||
}
|
}
|
||||||
// convert to absolute path
|
// convert to absolute path
|
||||||
if cf.name == '-I' || cf.name == '-L' || value.ends_with('.o') {
|
if cf.name == '-I' || cf.name == '-L' || value.ends_with('.o') {
|
||||||
value = '"'+os.realpath(value)+'"'
|
value = '"' + os.realpath(value) + '"'
|
||||||
}
|
}
|
||||||
return '$cf.name $value'.trim_space()
|
return '$cf.name $value'.trim_space()
|
||||||
}
|
}
|
||||||
|
@ -71,12 +67,7 @@ fn (table &Table) has_cflag(cflag CFlag) bool {
|
||||||
// parse the flags to (table.cflags) []CFlag
|
// parse the flags to (table.cflags) []CFlag
|
||||||
// Note: clean up big time (joe-c)
|
// Note: clean up big time (joe-c)
|
||||||
fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
||||||
allowed_flags := [
|
allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L', ]
|
||||||
'framework',
|
|
||||||
'library',
|
|
||||||
'Wa', 'Wl', 'Wp',
|
|
||||||
'I', 'l', 'L',
|
|
||||||
]
|
|
||||||
flag_orig := cflag.trim_space()
|
flag_orig := cflag.trim_space()
|
||||||
mut flag := flag_orig
|
mut flag := flag_orig
|
||||||
if flag == '' {
|
if flag == '' {
|
||||||
|
@ -84,7 +75,9 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
||||||
}
|
}
|
||||||
mut fos := ''
|
mut fos := ''
|
||||||
if flag.starts_with('linux') || flag.starts_with('darwin') || flag.starts_with('freebsd') || flag.starts_with('windows') {
|
if flag.starts_with('linux') || flag.starts_with('darwin') || flag.starts_with('freebsd') || flag.starts_with('windows') {
|
||||||
pos := flag.index(' ') or { return none }
|
pos := flag.index(' ') or {
|
||||||
|
return none
|
||||||
|
}
|
||||||
fos = flag[..pos].trim_space()
|
fos = flag[..pos].trim_space()
|
||||||
flag = flag[pos..].trim_space()
|
flag = flag[pos..].trim_space()
|
||||||
}
|
}
|
||||||
|
@ -93,7 +86,7 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
||||||
mut value := ''
|
mut value := ''
|
||||||
if flag[0] == `-` {
|
if flag[0] == `-` {
|
||||||
for f in allowed_flags {
|
for f in allowed_flags {
|
||||||
i := 1+f.len
|
i := 1 + f.len
|
||||||
if i <= flag.len && f == flag[1..i] {
|
if i <= flag.len && f == flag[1..i] {
|
||||||
name = flag[..i].trim_space()
|
name = flag[..i].trim_space()
|
||||||
flag = flag[i..].trim_space()
|
flag = flag[i..].trim_space()
|
||||||
|
@ -101,20 +94,24 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut index := flag.index(' -') or { -1 }
|
mut index := flag.index(' -') or {
|
||||||
|
-1
|
||||||
|
}
|
||||||
for index > -1 {
|
for index > -1 {
|
||||||
mut has_next := false
|
mut has_next := false
|
||||||
for f in allowed_flags {
|
for f in allowed_flags {
|
||||||
i := index+2+f.len
|
i := index + 2 + f.len
|
||||||
if i <= flag.len && f == flag[index+2..i] {
|
if i <= flag.len && f == flag[index + 2..i] {
|
||||||
value = flag[..index+1].trim_space()
|
value = flag[..index + 1].trim_space()
|
||||||
flag = flag[index+1..].trim_space()
|
flag = flag[index + 1..].trim_space()
|
||||||
has_next = true
|
has_next = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if has_next { break }
|
if has_next {
|
||||||
index = flag.index_after(' -', index+1)
|
break
|
||||||
|
}
|
||||||
|
index = flag.index_after(' -', index + 1)
|
||||||
}
|
}
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
value = flag.trim_space()
|
value = flag.trim_space()
|
||||||
|
@ -124,9 +121,9 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
||||||
return error('bad #flag `$flag_orig`: missing $hint after `$name`')
|
return error('bad #flag `$flag_orig`: missing $hint after `$name`')
|
||||||
}
|
}
|
||||||
cf := CFlag{
|
cf := CFlag{
|
||||||
mod: mod,
|
mod: mod
|
||||||
os: fos,
|
os: fos
|
||||||
name: name,
|
name: name
|
||||||
value: value
|
value: value
|
||||||
}
|
}
|
||||||
if !table.has_cflag(cf) {
|
if !table.has_cflag(cf) {
|
||||||
|
@ -139,13 +136,18 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: implement msvc specific c_options_before_target and c_options_after_target ...
|
// TODO: implement msvc specific c_options_before_target and c_options_after_target ...
|
||||||
fn (cflags []CFlag) c_options_before_target_msvc() string { return '' }
|
fn (cflags []CFlag) c_options_before_target_msvc() string {
|
||||||
fn (cflags []CFlag) c_options_after_target_msvc() string { return '' }
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (cflags []CFlag) c_options_after_target_msvc() string {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
fn (cflags []CFlag) c_options_before_target() string {
|
fn (cflags []CFlag) c_options_before_target() string {
|
||||||
// -I flags, optimization flags and so on
|
// -I flags, optimization flags and so on
|
||||||
mut args:=[]string
|
mut args := []string
|
||||||
for flag in cflags {
|
for flag in cflags {
|
||||||
if flag.name != '-l' {
|
if flag.name != '-l' {
|
||||||
args << flag.format()
|
args << flag.format()
|
||||||
|
@ -156,7 +158,7 @@ fn (cflags []CFlag) c_options_before_target() string {
|
||||||
|
|
||||||
fn (cflags []CFlag) c_options_after_target() string {
|
fn (cflags []CFlag) c_options_after_target() string {
|
||||||
// -l flags (libs)
|
// -l flags (libs)
|
||||||
mut args:=[]string
|
mut args := []string
|
||||||
for flag in cflags {
|
for flag in cflags {
|
||||||
if flag.name == '-l' {
|
if flag.name == '-l' {
|
||||||
args << flag.format()
|
args << flag.format()
|
||||||
|
@ -166,7 +168,7 @@ fn (cflags []CFlag) c_options_after_target() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (cflags []CFlag) c_options_without_object_files() string {
|
fn (cflags []CFlag) c_options_without_object_files() string {
|
||||||
mut args:=[]string
|
mut args := []string
|
||||||
for flag in cflags {
|
for flag in cflags {
|
||||||
if flag.value.ends_with('.o') || flag.value.ends_with('.obj') {
|
if flag.value.ends_with('.o') || flag.value.ends_with('.obj') {
|
||||||
continue
|
continue
|
||||||
|
@ -177,7 +179,7 @@ fn (cflags []CFlag) c_options_without_object_files() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (cflags []CFlag) c_options_only_object_files() string {
|
fn (cflags []CFlag) c_options_only_object_files() string {
|
||||||
mut args:=[]string
|
mut args := []string
|
||||||
for flag in cflags {
|
for flag in cflags {
|
||||||
if flag.value.ends_with('.o') || flag.value.ends_with('.obj') {
|
if flag.value.ends_with('.o') || flag.value.ends_with('.obj') {
|
||||||
args << flag.format()
|
args << flag.format()
|
||||||
|
@ -185,3 +187,4 @@ fn (cflags []CFlag) c_options_only_object_files() string {
|
||||||
}
|
}
|
||||||
return args.join(' ')
|
return args.join(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -356,19 +356,19 @@ fn platform_postfix_to_ifdefguard(name string) string {
|
||||||
'.v'{
|
'.v'{
|
||||||
''
|
''
|
||||||
} // no guard needed
|
} // no guard needed
|
||||||
'_win.v','_windows.v'{
|
'_win.v', '_windows.v'{
|
||||||
'#ifdef _WIN32'
|
'#ifdef _WIN32'
|
||||||
}
|
}
|
||||||
'_nix.v'{
|
'_nix.v'{
|
||||||
'#ifndef _WIN32'
|
'#ifndef _WIN32'
|
||||||
}
|
}
|
||||||
'_lin.v','_linux.v'{
|
'_lin.v', '_linux.v'{
|
||||||
'#ifdef __linux__'
|
'#ifdef __linux__'
|
||||||
}
|
}
|
||||||
'_mac.v','_darwin.v'{
|
'_mac.v', '_darwin.v'{
|
||||||
'#ifdef __APPLE__'
|
'#ifdef __APPLE__'
|
||||||
}
|
}
|
||||||
'_bsd.v','_freebsd.v '{
|
'_bsd.v', '_freebsd.v '{
|
||||||
'#ifdef __FreeBSD__'
|
'#ifdef __FreeBSD__'
|
||||||
}
|
}
|
||||||
'_solaris.v'{
|
'_solaris.v'{
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
c_common_macros = '
|
||||||
c_common_macros = '
|
|
||||||
|
|
||||||
#define EMPTY_STRUCT_DECLARATION
|
#define EMPTY_STRUCT_DECLARATION
|
||||||
#define EMPTY_STRUCT_INITIALIZATION 0
|
#define EMPTY_STRUCT_INITIALIZATION 0
|
||||||
|
@ -23,8 +22,7 @@ c_common_macros = '
|
||||||
|
|
||||||
#define OPTION_CAST(x) (x)
|
#define OPTION_CAST(x) (x)
|
||||||
'
|
'
|
||||||
|
c_headers = '
|
||||||
c_headers = '
|
|
||||||
|
|
||||||
//#include <inttypes.h> // int64_t etc
|
//#include <inttypes.h> // int64_t etc
|
||||||
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
||||||
|
@ -91,7 +89,7 @@ c_headers = '
|
||||||
#include <sys/wait.h> // os__wait uses wait on nix
|
#include <sys/wait.h> // os__wait uses wait on nix
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
$c_common_macros
|
$c_common_macros
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define WINVER 0x0600
|
#define WINVER 0x0600
|
||||||
|
@ -146,8 +144,7 @@ byteptr g_str_buf;
|
||||||
int load_so(byteptr);
|
int load_so(byteptr);
|
||||||
void reload_so();
|
void reload_so();
|
||||||
'
|
'
|
||||||
|
js_headers = '
|
||||||
js_headers = '
|
|
||||||
|
|
||||||
var array_string = function() {}
|
var array_string = function() {}
|
||||||
var array_byte = function() {}
|
var array_byte = function() {}
|
||||||
|
@ -170,9 +167,7 @@ var map_string = function() {}
|
||||||
var map_int = function() {}
|
var map_int = function() {}
|
||||||
|
|
||||||
'
|
'
|
||||||
|
c_builtin_types = '
|
||||||
|
|
||||||
c_builtin_types = '
|
|
||||||
|
|
||||||
//#include <inttypes.h> // int64_t etc
|
//#include <inttypes.h> // int64_t etc
|
||||||
//#include <stdint.h> // int64_t etc
|
//#include <stdint.h> // int64_t etc
|
||||||
|
@ -211,8 +206,7 @@ typedef map map_string;
|
||||||
#define false 0
|
#define false 0
|
||||||
#endif
|
#endif
|
||||||
'
|
'
|
||||||
|
bare_c_headers = '
|
||||||
bare_c_headers = '
|
|
||||||
|
|
||||||
$c_common_macros
|
$c_common_macros
|
||||||
|
|
||||||
|
@ -223,4 +217,3 @@ void sys_exit (int);
|
||||||
'
|
'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,49 +4,50 @@ import (
|
||||||
os
|
os
|
||||||
term
|
term
|
||||||
)
|
)
|
||||||
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// NB: The code in this file is organized in layers (between the ///// lines).
|
// NB: The code in this file is organized in layers (between the ///// lines).
|
||||||
// This allows for easier keeping in sync of error/warn functions.
|
// This allows for easier keeping in sync of error/warn functions.
|
||||||
// The functions in each of the layers, call the functions from the layers *below*.
|
// The functions in each of the layers, call the functions from the layers *below*.
|
||||||
// The functions in each of the layers, also have more details about the warn/error situation,
|
// The functions in each of the layers, also have more details about the warn/error situation,
|
||||||
// so they can display more informative message, so please call the lowest level variant you can.
|
// so they can display more informative message, so please call the lowest level variant you can.
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// TLDR: If you have a token index, call:
|
// TLDR: If you have a token index, call:
|
||||||
// p.error_with_token_index(msg, token_index)
|
// p.error_with_token_index(msg, token_index)
|
||||||
// ... not just :
|
// ... not just :
|
||||||
// p.error(msg)
|
// p.error(msg)
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
fn (p mut Parser) error(s string) {
|
fn (p mut Parser) error(s string) {
|
||||||
// no positioning info, so just assume that the last token was the culprit:
|
// no positioning info, so just assume that the last token was the culprit:
|
||||||
p.error_with_token_index(s, p.token_idx-1 )
|
p.error_with_token_index(s, p.token_idx - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) warn(s string) {
|
fn (p mut Parser) warn(s string) {
|
||||||
p.warn_with_token_index(s, p.token_idx-1 )
|
p.warn_with_token_index(s, p.token_idx - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) production_error_with_token_index(e string, tokenindex int) {
|
fn (p mut Parser) production_error_with_token_index(e string, tokenindex int) {
|
||||||
if p.pref.is_prod {
|
if p.pref.is_prod {
|
||||||
p.error_with_token_index( e, tokenindex )
|
p.error_with_token_index(e, tokenindex)
|
||||||
}else {
|
}
|
||||||
p.warn_with_token_index( e, tokenindex )
|
else {
|
||||||
|
p.warn_with_token_index(e, tokenindex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) error_with_token_index(s string, tokenindex int) {
|
fn (p mut Parser) error_with_token_index(s string, tokenindex int) {
|
||||||
p.error_with_position(s, p.scanner.get_scanner_pos_of_token( p.tokens[ tokenindex ] ) )
|
p.error_with_position(s, p.scanner.get_scanner_pos_of_token(p.tokens[tokenindex]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) warn_with_token_index(s string, tokenindex int) {
|
fn (p mut Parser) warn_with_token_index(s string, tokenindex int) {
|
||||||
p.warn_with_position(s, p.scanner.get_scanner_pos_of_token( p.tokens[ tokenindex ] ) )
|
p.warn_with_position(s, p.scanner.get_scanner_pos_of_token(p.tokens[tokenindex]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) error_with_position(s string, sp ScannerPos) {
|
fn (p mut Parser) error_with_position(s string, sp ScannerPos) {
|
||||||
p.print_error_context()
|
p.print_error_context()
|
||||||
e := normalized_error( s )
|
e := normalized_error(s)
|
||||||
p.scanner.goto_scanner_position( sp )
|
p.scanner.goto_scanner_position(sp)
|
||||||
p.scanner.error_with_col(e, sp.pos - sp.last_nl_pos)
|
p.scanner.error_with_col(e, sp.pos - sp.last_nl_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +57,10 @@ fn (p mut Parser) warn_with_position(s string, sp ScannerPos) {
|
||||||
}
|
}
|
||||||
// on a warning, restore the scanner state after printing the warning:
|
// on a warning, restore the scanner state after printing the warning:
|
||||||
cpos := p.scanner.get_scanner_pos()
|
cpos := p.scanner.get_scanner_pos()
|
||||||
e := normalized_error( s )
|
e := normalized_error(s)
|
||||||
p.scanner.goto_scanner_position( sp )
|
p.scanner.goto_scanner_position(sp)
|
||||||
p.scanner.warn_with_col(e, sp.pos - sp.last_nl_pos)
|
p.scanner.warn_with_col(e, sp.pos - sp.last_nl_pos)
|
||||||
p.scanner.goto_scanner_position( cpos )
|
p.scanner.goto_scanner_position(cpos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s &Scanner) error(msg string) {
|
fn (s &Scanner) error(msg string) {
|
||||||
|
@ -73,14 +74,14 @@ fn (s &Scanner) warn(msg string) {
|
||||||
fn (s &Scanner) warn_with_col(msg string, col int) {
|
fn (s &Scanner) warn_with_col(msg string, col int) {
|
||||||
fullpath := s.get_error_filepath()
|
fullpath := s.get_error_filepath()
|
||||||
color_on := s.is_color_output_on()
|
color_on := s.is_color_output_on()
|
||||||
final_message := if color_on { term.bold(term.bright_blue( msg )) } else { msg }
|
final_message := if color_on { term.bold(term.bright_blue(msg)) } else { msg }
|
||||||
eprintln('warning: ${fullpath}:${s.line_nr+1}:${col}: $final_message')
|
eprintln('warning: ${fullpath}:${s.line_nr+1}:${col}: $final_message')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s &Scanner) error_with_col(msg string, col int) {
|
fn (s &Scanner) error_with_col(msg string, col int) {
|
||||||
fullpath := s.get_error_filepath()
|
fullpath := s.get_error_filepath()
|
||||||
color_on := s.is_color_output_on()
|
color_on := s.is_color_output_on()
|
||||||
final_message := if color_on { term.red( term.bold( msg ) ) } else { msg }
|
final_message := if color_on { term.red(term.bold(msg)) } else { msg }
|
||||||
// The filepath:line:col: format is the default C compiler
|
// The filepath:line:col: format is the default C compiler
|
||||||
// error output format. It allows editors and IDE's like
|
// error output format. It allows editors and IDE's like
|
||||||
// emacs to quickly find the errors in the output
|
// emacs to quickly find the errors in the output
|
||||||
|
@ -88,65 +89,79 @@ fn (s &Scanner) error_with_col(msg string, col int) {
|
||||||
// NB: using only the filename may lead to inability of IDE/editors
|
// NB: using only the filename may lead to inability of IDE/editors
|
||||||
// to find the source file, when the IDE has a different working folder than v itself.
|
// to find the source file, when the IDE has a different working folder than v itself.
|
||||||
eprintln('${fullpath}:${s.line_nr + 1}:${col}: $final_message')
|
eprintln('${fullpath}:${s.line_nr + 1}:${col}: $final_message')
|
||||||
|
|
||||||
if s.print_line_on_error && s.nlines > 0 {
|
if s.print_line_on_error && s.nlines > 0 {
|
||||||
context_start_line := imax(0, (s.line_nr - error_context_before ))
|
context_start_line := imax(0, (s.line_nr - error_context_before))
|
||||||
context_end_line := imin(s.nlines-1, (s.line_nr + error_context_after + 1 ))
|
context_end_line := imin(s.nlines - 1, (s.line_nr + error_context_after + 1))
|
||||||
for cline := context_start_line; cline < context_end_line; cline++ {
|
for cline := context_start_line; cline < context_end_line; cline++ {
|
||||||
line := '${(cline+1):5d}| ' + s.line( cline )
|
line := '${(cline+1):5d}| ' + s.line(cline)
|
||||||
coloredline := if cline == s.line_nr && color_on { term.red(line) } else { line }
|
coloredline := if cline == s.line_nr && color_on { term.red(line) } else { line }
|
||||||
eprintln( coloredline )
|
eprintln(coloredline)
|
||||||
if cline != s.line_nr { continue }
|
if cline != s.line_nr {
|
||||||
|
continue
|
||||||
|
}
|
||||||
// The pointerline should have the same spaces/tabs as the offending
|
// The pointerline should have the same spaces/tabs as the offending
|
||||||
// line, so that it prints the ^ character exactly on the *same spot*
|
// line, so that it prints the ^ character exactly on the *same spot*
|
||||||
// where it is needed. That is the reason we can not just
|
// where it is needed. That is the reason we can not just
|
||||||
// use strings.repeat(` `, col) to form it.
|
// use strings.repeat(` `, col) to form it.
|
||||||
mut pointerline := []string
|
mut pointerline := []string
|
||||||
for i , c in line {
|
for i, c in line {
|
||||||
if i < col {
|
if i < col {
|
||||||
x := if c.is_space() { c } else { ` ` }
|
x := if c.is_space() { c } else { ` ` }
|
||||||
pointerline << x.str()
|
pointerline << x.str()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pointerline << if color_on { term.bold( term.blue('^') ) } else { '^' }
|
pointerline << if color_on { term.bold(term.blue('^')) } else { '^' }
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
eprintln( ' ' + pointerline.join('') )
|
eprintln(' ' + pointerline.join(''))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// / Misc error helper functions, can be called by any of the functions above
|
||||||
|
[inline]
|
||||||
|
fn (p &Parser) cur_tok_index() int {
|
||||||
|
return p.token_idx - 1
|
||||||
|
}
|
||||||
|
|
||||||
/// Misc error helper functions, can be called by any of the functions above
|
[inline]
|
||||||
|
fn imax(a, b int) int {
|
||||||
|
return if a > b { a } else { b }
|
||||||
|
}
|
||||||
|
|
||||||
[inline] fn (p &Parser) cur_tok_index() int { return p.token_idx - 1 }
|
[inline]
|
||||||
[inline] fn imax(a,b int) int { return if a > b { a } else { b } }
|
fn imin(a, b int) int {
|
||||||
[inline] fn imin(a,b int) int { return if a < b { a } else { b } }
|
return if a < b { a } else { b }
|
||||||
|
}
|
||||||
|
|
||||||
fn (s &Scanner) get_error_filepath() string {
|
fn (s &Scanner) get_error_filepath() string {
|
||||||
verror_paths_override := os.getenv('VERROR_PATHS')
|
verror_paths_override := os.getenv('VERROR_PATHS')
|
||||||
use_relative_paths := match verror_paths_override {
|
use_relative_paths := match verror_paths_override {
|
||||||
'relative' { true }
|
'relative'{
|
||||||
'absolute' { false }
|
true
|
||||||
else { s.print_rel_paths_on_error }
|
}
|
||||||
}
|
'absolute'{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.print_rel_paths_on_error}}
|
||||||
if use_relative_paths {
|
if use_relative_paths {
|
||||||
workdir := os.getwd() + os.path_separator
|
workdir := os.getwd() + os.path_separator
|
||||||
if s.file_path.starts_with(workdir) {
|
if s.file_path.starts_with(workdir) {
|
||||||
return s.file_path.replace( workdir, '')
|
return s.file_path.replace(workdir, '')
|
||||||
}
|
}
|
||||||
return s.file_path
|
return s.file_path
|
||||||
}
|
}
|
||||||
return os.realpath( s.file_path )
|
return os.realpath(s.file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s &Scanner) is_color_output_on() bool {
|
fn (s &Scanner) is_color_output_on() bool {
|
||||||
return s.print_colored_error && term.can_show_color_on_stderr()
|
return s.print_colored_error && term.can_show_color_on_stderr()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) print_error_context(){
|
fn (p mut Parser) print_error_context() {
|
||||||
// Dump all vars and types for debugging
|
// Dump all vars and types for debugging
|
||||||
if p.pref.is_debug {
|
if p.pref.is_debug {
|
||||||
// os.write_to_file('/var/tmp/lang.types', '')//pes(p.table.types))
|
// os.write_to_file('/var/tmp/lang.types', '')//pes(p.table.types))
|
||||||
|
@ -158,14 +173,14 @@ fn (p mut Parser) print_error_context(){
|
||||||
p.cgen.save()
|
p.cgen.save()
|
||||||
// V up hint
|
// V up hint
|
||||||
cur_path := os.getwd()
|
cur_path := os.getwd()
|
||||||
if !p.pref.is_repl && !p.pref.is_test && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){
|
if !p.pref.is_repl && !p.pref.is_test && (p.file_path.contains('v/compiler') || cur_path.contains('v/compiler')) {
|
||||||
println('\n=========================')
|
println('\n=========================')
|
||||||
println('It looks like you are building V. It is being frequently updated every day.')
|
println('It looks like you are building V. It is being frequently updated every day.')
|
||||||
println('If you didn\'t modify V\'s code, most likely there was a change that ')
|
println("If you didn\'t modify V\'s code, most likely there was a change that ")
|
||||||
println('lead to this error.')
|
println('lead to this error.')
|
||||||
println('\nRun `v up`, that will most likely fix it.')
|
println('\nRun `v up`, that will most likely fix it.')
|
||||||
//println('\nIf this doesn\'t help, re-install V from source or download a precompiled' + ' binary from\nhttps://vlang.io.')
|
// println('\nIf this doesn\'t help, re-install V from source or download a precompiled' + ' binary from\nhttps://vlang.io.')
|
||||||
println('\nIf this doesn\'t help, please create a GitHub issue.')
|
println("\nIf this doesn\'t help, please create a GitHub issue.")
|
||||||
println('=========================\n')
|
println('=========================\n')
|
||||||
}
|
}
|
||||||
if p.pref.is_debug {
|
if p.pref.is_debug {
|
||||||
|
@ -176,30 +191,25 @@ fn (p mut Parser) print_error_context(){
|
||||||
|
|
||||||
fn normalized_error(s string) string {
|
fn normalized_error(s string) string {
|
||||||
// Print `[]int` instead of `array_int` in errors
|
// Print `[]int` instead of `array_int` in errors
|
||||||
mut res := s.replace('array_', '[]')
|
mut res := s.replace('array_', '[]').replace('__', '.').replace('Option_', '?').replace('main.', '')
|
||||||
.replace('__', '.')
|
|
||||||
.replace('Option_', '?')
|
|
||||||
.replace('main.', '')
|
|
||||||
if res.contains('_V_MulRet_') {
|
if res.contains('_V_MulRet_') {
|
||||||
res = res.replace('_V_MulRet_', '(').replace('_V_', ', ')
|
res = res.replace('_V_MulRet_', '(').replace('_V_', ', ')
|
||||||
res = res[..res.len-1] + ')"'
|
res = res[..res.len - 1] + ')"'
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// The goal of ScannerPos is to track the current scanning position,
|
// The goal of ScannerPos is to track the current scanning position,
|
||||||
// so that if there is an error found later, v could show a more accurate
|
// so that if there is an error found later, v could show a more accurate
|
||||||
// position about where the error initially was.
|
// position about where the error initially was.
|
||||||
// NB: The fields of ScannerPos *should be kept synchronized* with the
|
// NB: The fields of ScannerPos *should be kept synchronized* with the
|
||||||
// corresponding fields in Scanner.
|
// corresponding fields in Scanner.
|
||||||
|
|
||||||
struct ScannerPos {
|
struct ScannerPos {
|
||||||
mut:
|
mut:
|
||||||
pos int
|
pos int
|
||||||
line_nr int
|
line_nr int
|
||||||
last_nl_pos int
|
last_nl_pos int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s ScannerPos) str() string {
|
pub fn (s ScannerPos) str() string {
|
||||||
|
@ -207,7 +217,11 @@ pub fn (s ScannerPos) str() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s &Scanner) get_scanner_pos() ScannerPos {
|
fn (s &Scanner) get_scanner_pos() ScannerPos {
|
||||||
return ScannerPos{ pos: s.pos line_nr: s.line_nr last_nl_pos: s.last_nl_pos }
|
return ScannerPos{
|
||||||
|
pos: s.pos
|
||||||
|
line_nr: s.line_nr
|
||||||
|
last_nl_pos: s.last_nl_pos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s mut Scanner) goto_scanner_position(scp ScannerPos) {
|
fn (s mut Scanner) goto_scanner_position(scp ScannerPos) {
|
||||||
|
@ -217,7 +231,7 @@ fn (s mut Scanner) goto_scanner_position(scp ScannerPos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s &Scanner) get_last_nl_from_pos(_pos int) int {
|
fn (s &Scanner) get_last_nl_from_pos(_pos int) int {
|
||||||
pos := if _pos >= s.text.len { s.text.len-1 } else { _pos }
|
pos := if _pos >= s.text.len { s.text.len - 1 } else { _pos }
|
||||||
for i := pos; i >= 0; i-- {
|
for i := pos; i >= 0; i-- {
|
||||||
if s.text[i] == `\n` {
|
if s.text[i] == `\n` {
|
||||||
return i
|
return i
|
||||||
|
@ -234,33 +248,27 @@ fn (s &Scanner) get_scanner_pos_of_token(tok &Token) ScannerPos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////
|
// /////////////////////////////
|
||||||
|
|
||||||
fn (p mut Parser) mutable_arg_error(i int, arg Var, f Fn) {
|
fn (p mut Parser) mutable_arg_error(i int, arg Var, f Fn) {
|
||||||
mut dots_example := 'mut $p.lit'
|
mut dots_example := 'mut $p.lit'
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
dots_example = '.., ' + dots_example
|
dots_example = '.., ' + dots_example
|
||||||
}
|
}
|
||||||
if i < f.args.len - 1 {
|
if i < f.args.len - 1 {
|
||||||
dots_example = dots_example + ',..'
|
dots_example = dots_example + ',..'
|
||||||
}
|
}
|
||||||
p.error('`$arg.name` is a mutable argument, you need to provide `mut`: ' +
|
p.error('`$arg.name` is a mutable argument, you need to provide `mut`: ' + '`$f.name ($dots_example)`')
|
||||||
'`$f.name ($dots_example)`')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
warn_match_arrow = '=> is no longer needed in match statements, use\n' +
|
warn_match_arrow = '=> is no longer needed in match statements, use\n' + 'match foo {
|
||||||
'match foo {
|
|
||||||
1 { bar }
|
1 { bar }
|
||||||
2 { baz }
|
2 { baz }
|
||||||
else { ... }
|
else { ... }
|
||||||
}'
|
}'
|
||||||
//make_receiver_mutable =
|
// make_receiver_mutable =
|
||||||
|
|
||||||
err_used_as_value = 'used as value'
|
err_used_as_value = 'used as value'
|
||||||
|
and_or_error = 'use `()` to make the boolean expression clear\n' + 'for example: `(a && b) || c` instead of `a && b || c`'
|
||||||
and_or_error = 'use `()` to make the boolean expression clear\n' +
|
err_modify_bitfield = 'to modify a bitfield flag use the methods: set, clear, toggle. and to check for flag use: has'
|
||||||
'for example: `(a && b) || c` instead of `a && b || c`'
|
|
||||||
|
|
||||||
err_modify_bitfield = 'to modify a bitfield flag use the methods: set, clear, toggle. and to check for flag use: has'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
pub fn get_v_options_and_main_command(args []string) ([]string,string) {
|
pub fn get_v_options_and_main_command(args []string) ([]string,string) {
|
||||||
|
@ -12,12 +11,16 @@ pub fn get_v_options_and_main_command(args []string) ([]string,string) {
|
||||||
if !a.starts_with('-') {
|
if !a.starts_with('-') {
|
||||||
potential_commands << a
|
potential_commands << a
|
||||||
continue
|
continue
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
options << a
|
options << a
|
||||||
if a in ['-o', '-os', '-cc', '-cflags', '-d'] { i++ }
|
if a in ['-o', '-os', '-cc', '-cflags', '-d'] {
|
||||||
|
i++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// potential_commands[0] is always the executable itself, so ignore it
|
// potential_commands[0] is always the executable itself, so ignore it
|
||||||
command := if potential_commands.len > 1 { potential_commands[1] } else { '' }
|
command := if potential_commands.len > 1 { potential_commands[1] } else { '' }
|
||||||
return options, command
|
return options,command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,35 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Directed acyclic graph
|
// Directed acyclic graph
|
||||||
// this implementation is specifically suited to ordering dependencies
|
// this implementation is specifically suited to ordering dependencies
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
struct DepGraphNode {
|
struct DepGraphNode {
|
||||||
mut:
|
mut:
|
||||||
name string
|
name string
|
||||||
deps []string
|
deps []string
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DepGraph {
|
struct DepGraph {
|
||||||
//pub:
|
// pub:
|
||||||
mut:
|
mut:
|
||||||
acyclic bool
|
acyclic bool
|
||||||
nodes []DepGraphNode
|
nodes []DepGraphNode
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DepSet {
|
struct DepSet {
|
||||||
mut:
|
mut:
|
||||||
items []string
|
items []string
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn(dset mut DepSet) add(item string) {
|
pub fn (dset mut DepSet) add(item string) {
|
||||||
dset.items << item
|
dset.items << item
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn(dset &DepSet) diff(otherset DepSet) DepSet {
|
pub fn (dset &DepSet) diff(otherset DepSet) DepSet {
|
||||||
mut diff := DepSet{}
|
mut diff := DepSet{
|
||||||
|
}
|
||||||
for item in dset.items {
|
for item in dset.items {
|
||||||
if !item in otherset.items {
|
if !item in otherset.items {
|
||||||
diff.items << item
|
diff.items << item
|
||||||
|
@ -39,7 +38,7 @@ pub fn(dset &DepSet) diff(otherset DepSet) DepSet {
|
||||||
return diff
|
return diff
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn(dset &DepSet) size() int {
|
pub fn (dset &DepSet) size() int {
|
||||||
return dset.items.len
|
return dset.items.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,37 +48,34 @@ pub fn new_dep_graph() &DepGraph {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (graph mut DepGraph) add(mod string, deps []string) {
|
||||||
pub fn(graph mut DepGraph) add(mod string, deps []string) {
|
|
||||||
graph.nodes << DepGraphNode{
|
graph.nodes << DepGraphNode{
|
||||||
name: mod,
|
name: mod
|
||||||
deps: deps.clone()
|
deps: deps.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn(graph &DepGraph) resolve() &DepGraph {
|
pub fn (graph &DepGraph) resolve() &DepGraph {
|
||||||
mut node_names := map[string]DepGraphNode
|
mut node_names := map[string]DepGraphNode
|
||||||
mut node_deps := map[string]DepSet
|
mut node_deps := map[string]DepSet
|
||||||
|
|
||||||
for _, node in graph.nodes {
|
for _, node in graph.nodes {
|
||||||
node_names[node.name] = node
|
node_names[node.name] = node
|
||||||
|
mut dep_set := DepSet{
|
||||||
mut dep_set := DepSet{}
|
}
|
||||||
for _, dep in node.deps {
|
for _, dep in node.deps {
|
||||||
dep_set.add(dep)
|
dep_set.add(dep)
|
||||||
}
|
}
|
||||||
node_deps[node.name] = dep_set
|
node_deps[node.name] = dep_set
|
||||||
}
|
}
|
||||||
|
|
||||||
mut resolved := new_dep_graph()
|
mut resolved := new_dep_graph()
|
||||||
for node_deps.size != 0 {
|
for node_deps.size != 0 {
|
||||||
mut ready_set := DepSet{}
|
mut ready_set := DepSet{
|
||||||
|
}
|
||||||
for name, deps in node_deps {
|
for name, deps in node_deps {
|
||||||
if deps.size() == 0 {
|
if deps.size() == 0 {
|
||||||
ready_set.add(name)
|
ready_set.add(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ready_set.size() == 0 {
|
if ready_set.size() == 0 {
|
||||||
mut g := new_dep_graph()
|
mut g := new_dep_graph()
|
||||||
g.acyclic = false
|
g.acyclic = false
|
||||||
|
@ -88,25 +84,22 @@ pub fn(graph &DepGraph) resolve() &DepGraph {
|
||||||
}
|
}
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
for name in ready_set.items {
|
for name in ready_set.items {
|
||||||
node_deps.delete(name)
|
node_deps.delete(name)
|
||||||
resolved.nodes << node_names[name]
|
resolved.nodes << node_names[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, deps in node_deps {
|
for name, deps in node_deps {
|
||||||
node_deps[name] = deps.diff(ready_set)
|
node_deps[name] = deps.diff(ready_set)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn(graph &DepGraph) last_node() DepGraphNode {
|
pub fn (graph &DepGraph) last_node() DepGraphNode {
|
||||||
return graph.nodes[graph.nodes.len-1]
|
return graph.nodes[graph.nodes.len - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn(graph &DepGraph) display() string {
|
pub fn (graph &DepGraph) display() string {
|
||||||
mut out := '\n'
|
mut out := '\n'
|
||||||
for node in graph.nodes {
|
for node in graph.nodes {
|
||||||
for dep in node.deps {
|
for dep in node.deps {
|
||||||
|
@ -116,7 +109,7 @@ pub fn(graph &DepGraph) display() string {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn(graph &DepGraph) display_cycles() string {
|
pub fn (graph &DepGraph) display_cycles() string {
|
||||||
mut node_names := map[string]DepGraphNode
|
mut node_names := map[string]DepGraphNode
|
||||||
for node in graph.nodes {
|
for node in graph.nodes {
|
||||||
node_names[node.name] = node
|
node_names[node.name] = node
|
||||||
|
@ -124,7 +117,9 @@ pub fn(graph &DepGraph) display_cycles() string {
|
||||||
mut out := '\n'
|
mut out := '\n'
|
||||||
for node in graph.nodes {
|
for node in graph.nodes {
|
||||||
for dep in node.deps {
|
for dep in node.deps {
|
||||||
if !(dep in node_names) { continue }
|
if !(dep in node_names) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
dn := node_names[dep]
|
dn := node_names[dep]
|
||||||
if node.name in dn.deps {
|
if node.name in dn.deps {
|
||||||
out += ' * $node.name -> $dep\n'
|
out += ' * $node.name -> $dep\n'
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
fn (p mut Parser) enum_decl(no_name bool) {
|
fn (p mut Parser) enum_decl(no_name bool) {
|
||||||
|
@ -12,7 +11,7 @@ fn (p mut Parser) enum_decl(no_name bool) {
|
||||||
}
|
}
|
||||||
p.check(.key_enum)
|
p.check(.key_enum)
|
||||||
p.fspace()
|
p.fspace()
|
||||||
mut enum_name := p.check_name()
|
mut enum_name := p.check_name()
|
||||||
is_c := enum_name == 'C' && p.tok == .dot
|
is_c := enum_name == 'C' && p.tok == .dot
|
||||||
if is_c {
|
if is_c {
|
||||||
p.check(.dot)
|
p.check(.dot)
|
||||||
|
@ -44,7 +43,8 @@ fn (p mut Parser) enum_decl(no_name bool) {
|
||||||
p.next()
|
p.next()
|
||||||
val = p.lit.int()
|
val = p.lit.int()
|
||||||
p.next()
|
p.next()
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
p.next()
|
p.next()
|
||||||
enum_assign_tidx = p.cur_tok_index()
|
enum_assign_tidx = p.cur_tok_index()
|
||||||
p.error_with_token_index('only numbers are allowed in enum initializations', enum_assign_tidx)
|
p.error_with_token_index('only numbers are allowed in enum initializations', enum_assign_tidx)
|
||||||
|
@ -62,7 +62,7 @@ fn (p mut Parser) enum_decl(no_name bool) {
|
||||||
if is_flag && fields.len > 32 {
|
if is_flag && fields.len > 32 {
|
||||||
p.error('when an enum is used as bit field, it must have a max of 32 fields')
|
p.error('when an enum is used as bit field, it must have a max of 32 fields')
|
||||||
}
|
}
|
||||||
mut T := Type {
|
mut T := Type{
|
||||||
name: enum_name
|
name: enum_name
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
parent: 'int'
|
parent: 'int'
|
||||||
|
@ -89,9 +89,9 @@ fn (p mut Parser) check_enum_member_access() {
|
||||||
p.error('enum `$T.name` does not have value `$val`')
|
p.error('enum `$T.name` does not have value `$val`')
|
||||||
}
|
}
|
||||||
p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val)
|
p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val)
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
p.error('`$T.name` is not an enum')
|
p.error('`$T.name` is not an enum')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -718,7 +718,7 @@ fn (p mut Parser) factor() string {
|
||||||
// p.fgen('$sizeof_typ)')
|
// p.fgen('$sizeof_typ)')
|
||||||
return 'int'
|
return 'int'
|
||||||
}
|
}
|
||||||
.amp,.dot,.mul {
|
.amp, .dot, .mul {
|
||||||
// (dot is for enum vals: `.green`)
|
// (dot is for enum vals: `.green`)
|
||||||
return p.name_expr()
|
return p.name_expr()
|
||||||
}
|
}
|
||||||
|
@ -822,3 +822,4 @@ fn (p mut Parser) factor() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// { user | name: 'new name' }
|
// { user | name: 'new name' }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
fn (p mut Parser) for_st() {
|
fn (p mut Parser) for_st() {
|
||||||
|
@ -11,7 +10,7 @@ fn (p mut Parser) for_st() {
|
||||||
if p.tok != .lcbr {
|
if p.tok != .lcbr {
|
||||||
p.fspace()
|
p.fspace()
|
||||||
}
|
}
|
||||||
//debug := p.scanner.file_path.contains('r_draw')
|
// debug := p.scanner.file_path.contains('r_draw')
|
||||||
p.open_scope()
|
p.open_scope()
|
||||||
mut label := 0
|
mut label := 0
|
||||||
mut to := 0
|
mut to := 0
|
||||||
|
@ -70,18 +69,19 @@ fn (p mut Parser) for_st() {
|
||||||
p.check(.key_in)
|
p.check(.key_in)
|
||||||
p.fspace()
|
p.fspace()
|
||||||
tmp := p.get_tmp()
|
tmp := p.get_tmp()
|
||||||
mut typ, expr := p.tmp_expr()
|
mut typ,expr := p.tmp_expr()
|
||||||
is_arr := typ.starts_with('array_')
|
is_arr := typ.starts_with('array_')
|
||||||
is_map := typ.starts_with('map_')
|
is_map := typ.starts_with('map_')
|
||||||
is_str := typ == 'string'
|
is_str := typ == 'string'
|
||||||
is_variadic_arg := typ.starts_with('varg_')
|
is_variadic_arg := typ.starts_with('varg_')
|
||||||
if !is_arr && !is_str && !is_map && !is_variadic_arg {
|
if !is_arr && !is_str && !is_map && !is_variadic_arg {
|
||||||
p.error('cannot range over type `$typ`')
|
p.error('cannot range over type `$typ`')
|
||||||
}
|
}
|
||||||
if !is_variadic_arg {
|
if !is_variadic_arg {
|
||||||
if p.is_js {
|
if p.is_js {
|
||||||
p.genln('var $tmp = $expr;')
|
p.genln('var $tmp = $expr;')
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
p.genln('$typ $tmp = $expr;')
|
p.genln('$typ $tmp = $expr;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ fn (p mut Parser) for_st() {
|
||||||
p.gen_for_varg_header(i, expr, typ, val)
|
p.gen_for_varg_header(i, expr, typ, val)
|
||||||
}
|
}
|
||||||
else if is_arr {
|
else if is_arr {
|
||||||
typ = typ[6..].replace('_ptr','*')
|
typ = typ[6..].replace('_ptr', '*')
|
||||||
p.gen_for_header(i, tmp, typ, val)
|
p.gen_for_header(i, tmp, typ, val)
|
||||||
}
|
}
|
||||||
else if is_map {
|
else if is_map {
|
||||||
|
@ -109,7 +109,7 @@ fn (p mut Parser) for_st() {
|
||||||
if p.known_var(i) {
|
if p.known_var(i) {
|
||||||
p.error('redefinition of `$i`')
|
p.error('redefinition of `$i`')
|
||||||
}
|
}
|
||||||
p.register_var(Var {
|
p.register_var(Var{
|
||||||
name: i
|
name: i
|
||||||
typ: i_var_type
|
typ: i_var_type
|
||||||
is_mut: true
|
is_mut: true
|
||||||
|
@ -120,7 +120,7 @@ fn (p mut Parser) for_st() {
|
||||||
if p.known_var(val) {
|
if p.known_var(val) {
|
||||||
p.error('redefinition of `$val`')
|
p.error('redefinition of `$val`')
|
||||||
}
|
}
|
||||||
p.register_var(Var {
|
p.register_var(Var{
|
||||||
name: val
|
name: val
|
||||||
typ: typ
|
typ: typ
|
||||||
ptr: typ.contains('*')
|
ptr: typ.contains('*')
|
||||||
|
@ -134,9 +134,9 @@ fn (p mut Parser) for_st() {
|
||||||
p.check(.key_in)
|
p.check(.key_in)
|
||||||
p.fspace()
|
p.fspace()
|
||||||
tmp := p.get_tmp()
|
tmp := p.get_tmp()
|
||||||
mut typ, expr := p.tmp_expr()
|
mut typ,expr := p.tmp_expr()
|
||||||
is_range := p.tok == .dotdot
|
is_range := p.tok == .dotdot
|
||||||
is_variadic_arg := typ.starts_with('varg_')
|
is_variadic_arg := typ.starts_with('varg_')
|
||||||
mut range_end := ''
|
mut range_end := ''
|
||||||
if is_range {
|
if is_range {
|
||||||
p.check_types(typ, 'int')
|
p.check_types(typ, 'int')
|
||||||
|
@ -144,14 +144,13 @@ fn (p mut Parser) for_st() {
|
||||||
if p.pref.x64 {
|
if p.pref.x64 {
|
||||||
to = p.lit.int()
|
to = p.lit.int()
|
||||||
}
|
}
|
||||||
range_typ, range_expr := p.tmp_expr()
|
range_typ,range_expr := p.tmp_expr()
|
||||||
p.check_types(range_typ, 'int')
|
p.check_types(range_typ, 'int')
|
||||||
range_end = range_expr
|
range_end = range_expr
|
||||||
if p.pref.x64 {
|
if p.pref.x64 {
|
||||||
label = p.x64.gen_loop_start(expr.int())
|
label = p.x64.gen_loop_start(expr.int())
|
||||||
//to = range_expr.int() // TODO why empty?
|
// to = range_expr.int() // TODO why empty?
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
is_arr := typ.contains('array')
|
is_arr := typ.contains('array')
|
||||||
is_fixed := typ.starts_with('[')
|
is_fixed := typ.starts_with('[')
|
||||||
|
@ -162,7 +161,9 @@ fn (p mut Parser) for_st() {
|
||||||
if !is_variadic_arg {
|
if !is_variadic_arg {
|
||||||
if p.is_js {
|
if p.is_js {
|
||||||
p.genln('var $tmp = $expr;')
|
p.genln('var $tmp = $expr;')
|
||||||
} else if !is_fixed { // Don't copy if it's a fixed array
|
}
|
||||||
|
else if !is_fixed {
|
||||||
|
// Don't copy if it's a fixed array
|
||||||
p.genln('$typ $tmp = $expr;')
|
p.genln('$typ $tmp = $expr;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,7 +178,7 @@ fn (p mut Parser) for_st() {
|
||||||
p.gen_for_range_header(i, range_end, tmp, typ, val)
|
p.gen_for_range_header(i, range_end, tmp, typ, val)
|
||||||
}
|
}
|
||||||
else if is_arr {
|
else if is_arr {
|
||||||
typ = typ[6..].replace('_ptr','*')// all after `array_`
|
typ = typ[6..].replace('_ptr', '*') // all after `array_`
|
||||||
p.gen_for_header(i, tmp, typ, val)
|
p.gen_for_header(i, tmp, typ, val)
|
||||||
}
|
}
|
||||||
else if is_str {
|
else if is_str {
|
||||||
|
@ -194,7 +195,7 @@ fn (p mut Parser) for_st() {
|
||||||
if p.known_var(val) {
|
if p.known_var(val) {
|
||||||
p.error('redefinition of `$val`')
|
p.error('redefinition of `$val`')
|
||||||
}
|
}
|
||||||
p.register_var(Var {
|
p.register_var(Var{
|
||||||
name: val
|
name: val
|
||||||
typ: typ
|
typ: typ
|
||||||
ptr: typ.contains('*')
|
ptr: typ.contains('*')
|
||||||
|
@ -203,7 +204,8 @@ fn (p mut Parser) for_st() {
|
||||||
is_for_var: true
|
is_for_var: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// `for a < b {`
|
// `for a < b {`
|
||||||
p.gen('while (')
|
p.gen('while (')
|
||||||
p.check_types(p.bool_expression(), 'bool')
|
p.check_types(p.bool_expression(), 'bool')
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
module compiler
|
module compiler
|
||||||
|
// import filepath
|
||||||
//import filepath
|
// import compiler.x64
|
||||||
|
|
||||||
//import compiler.x64
|
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,7 @@ fn (p mut Parser) match_statement(is_expr bool) string {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.check(.comma)
|
p.check(.comma)
|
||||||
|
p.fspace()
|
||||||
got_comma = true
|
got_comma = true
|
||||||
}
|
}
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
// TODO replace with comptime code generation.
|
// TODO replace with comptime code generation.
|
||||||
// TODO remove cJSON dependency.
|
// TODO remove cJSON dependency.
|
||||||
// OLD: User decode_User(string js) {
|
// OLD: User decode_User(string js) {
|
||||||
|
@ -27,7 +25,7 @@ fn (p mut Parser) gen_json_for_type(typ Type) {
|
||||||
}
|
}
|
||||||
// println('gen_json_for_type( $typ.name )')
|
// println('gen_json_for_type( $typ.name )')
|
||||||
// Register decoder fn
|
// Register decoder fn
|
||||||
mut dec_fn := Fn {
|
mut dec_fn := Fn{
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
typ: 'Option_$typ.name'
|
typ: 'Option_$typ.name'
|
||||||
name: js_dec_name(t)
|
name: js_dec_name(t)
|
||||||
|
@ -38,19 +36,19 @@ fn (p mut Parser) gen_json_for_type(typ Type) {
|
||||||
}
|
}
|
||||||
// decode_TYPE funcs receive an actual cJSON* object to decode
|
// decode_TYPE funcs receive an actual cJSON* object to decode
|
||||||
// cJSON_Parse(str) call is added by the compiler
|
// cJSON_Parse(str) call is added by the compiler
|
||||||
arg := Var {
|
arg := Var{
|
||||||
typ: 'cJSON*'
|
typ: 'cJSON*'
|
||||||
}
|
}
|
||||||
dec_fn.args << arg
|
dec_fn.args << arg
|
||||||
p.table.register_fn(dec_fn)
|
p.table.register_fn(dec_fn)
|
||||||
// Register encoder fn
|
// Register encoder fn
|
||||||
mut enc_fn := Fn {
|
mut enc_fn := Fn{
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
typ: 'cJSON*'
|
typ: 'cJSON*'
|
||||||
name: js_enc_name(t)
|
name: js_enc_name(t)
|
||||||
}
|
}
|
||||||
// encode_TYPE funcs receive an object to encode
|
// encode_TYPE funcs receive an object to encode
|
||||||
enc_arg := Var {
|
enc_arg := Var{
|
||||||
typ: t
|
typ: t
|
||||||
}
|
}
|
||||||
enc_fn.args << enc_arg
|
enc_fn.args << enc_arg
|
||||||
|
@ -85,28 +83,20 @@ string res = tos2("");
|
||||||
if field.attr == 'skip' {
|
if field.attr == 'skip' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
name := if field.attr.starts_with('json:') {
|
name := if field.attr.starts_with('json:') { field.attr[5..] } else { field.name }
|
||||||
field.attr[5..]
|
|
||||||
} else {
|
|
||||||
field.name
|
|
||||||
}
|
|
||||||
field_type := p.table.find_type(field.typ)
|
field_type := p.table.find_type(field.typ)
|
||||||
_typ := field.typ.replace('*', '')
|
_typ := field.typ.replace('*', '')
|
||||||
enc_name := js_enc_name(_typ)
|
enc_name := js_enc_name(_typ)
|
||||||
if field.attr == 'raw' {
|
if field.attr == 'raw' {
|
||||||
dec += ' res->$field.name = tos2(cJSON_PrintUnformatted(' +
|
dec += ' res->$field.name = tos2(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));\n'
|
||||||
'js_get(root, "$name")));\n'
|
}
|
||||||
|
else {
|
||||||
} else {
|
|
||||||
// Now generate decoders for all field types in this struct
|
// Now generate decoders for all field types in this struct
|
||||||
// need to do it here so that these functions are generated first
|
// need to do it here so that these functions are generated first
|
||||||
p.gen_json_for_type(field_type)
|
p.gen_json_for_type(field_type)
|
||||||
|
|
||||||
dec_name := js_dec_name(_typ)
|
dec_name := js_dec_name(_typ)
|
||||||
|
|
||||||
if is_js_prim(_typ) {
|
if is_js_prim(_typ) {
|
||||||
dec += ' res->$field.name = $dec_name (js_get(' +
|
dec += ' res->$field.name = $dec_name (js_get(' + 'root, "$name"))'
|
||||||
'root, "$name"))'
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dec += ' $dec_name (js_get(root, "$name"), & (res->$field.name))'
|
dec += ' $dec_name (js_get(root, "$name"), & (res->$field.name))'
|
||||||
|
@ -116,16 +106,13 @@ string res = tos2("");
|
||||||
enc += ' cJSON_AddItemToObject(o, "$name",$enc_name (val.$field.name)); \n'
|
enc += ' cJSON_AddItemToObject(o, "$name",$enc_name (val.$field.name)); \n'
|
||||||
}
|
}
|
||||||
// cJSON_delete
|
// cJSON_delete
|
||||||
//p.cgen.fns << '$dec return opt_ok(res); \n}'
|
// p.cgen.fns << '$dec return opt_ok(res); \n}'
|
||||||
p.cgen.fns << '$dec return opt_ok(res, sizeof(*res)); \n}'
|
p.cgen.fns << '$dec return opt_ok(res, sizeof(*res)); \n}'
|
||||||
p.cgen.fns << '/*enc start*/ $enc return o;}'
|
p.cgen.fns << '/*enc start*/ $enc return o;}'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_js_prim(typ string) bool {
|
fn is_js_prim(typ string) bool {
|
||||||
return typ == 'int' || typ == 'string' ||
|
return typ == 'int' || typ == 'string' || typ == 'bool' || typ == 'f32' || typ == 'f64' || typ == 'i8' || typ == 'i16' || typ == 'i64' || typ == 'u16' || typ == 'u32' || typ == 'u64'
|
||||||
typ == 'bool' || typ == 'f32' || typ == 'f64' ||
|
|
||||||
typ == 'i8' || typ == 'i16' || typ == 'i64' ||
|
|
||||||
typ == 'u16' || typ == 'u32' || typ == 'u64'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) decode_array(array_type string) string {
|
fn (p mut Parser) decode_array(array_type string) string {
|
||||||
|
|
|
@ -7,10 +7,10 @@ fn (v &V) generate_hotcode_reloading_compiler_flags() []string {
|
||||||
mut a := []string
|
mut a := []string
|
||||||
if v.pref.is_live || v.pref.is_so {
|
if v.pref.is_live || v.pref.is_so {
|
||||||
// See 'man dlopen', and test running a GUI program compiled with -live
|
// See 'man dlopen', and test running a GUI program compiled with -live
|
||||||
if (v.os == .linux || os.user_os() == 'linux'){
|
if (v.os == .linux || os.user_os() == 'linux') {
|
||||||
a << '-rdynamic'
|
a << '-rdynamic'
|
||||||
}
|
}
|
||||||
if (v.os == .mac || os.user_os() == 'mac'){
|
if (v.os == .mac || os.user_os() == 'mac') {
|
||||||
a << '-flat_namespace'
|
a << '-flat_namespace'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ fn (v &V) generate_hotcode_reloading_declarations() {
|
||||||
if v.pref.is_live {
|
if v.pref.is_live {
|
||||||
cgen.genln('pthread_mutex_t live_fn_mutex = PTHREAD_MUTEX_INITIALIZER;')
|
cgen.genln('pthread_mutex_t live_fn_mutex = PTHREAD_MUTEX_INITIALIZER;')
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if v.pref.is_so {
|
if v.pref.is_so {
|
||||||
cgen.genln('HANDLE live_fn_mutex;')
|
cgen.genln('HANDLE live_fn_mutex;')
|
||||||
cgen.genln('
|
cgen.genln('
|
||||||
|
@ -45,7 +46,9 @@ void pthread_mutex_unlock(HANDLE *m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (v &V) generate_hotcode_reloading_main_caller() {
|
fn (v &V) generate_hotcode_reloading_main_caller() {
|
||||||
if !v.pref.is_live { return }
|
if !v.pref.is_live {
|
||||||
|
return
|
||||||
|
}
|
||||||
// We are in live code reload mode, so start the .so loader in the background
|
// We are in live code reload mode, so start the .so loader in the background
|
||||||
mut cgen := v.cgen
|
mut cgen := v.cgen
|
||||||
cgen.genln('')
|
cgen.genln('')
|
||||||
|
@ -57,9 +60,10 @@ fn (v &V) generate_hotcode_reloading_main_caller() {
|
||||||
cgen.genln(' load_so(live_library_name);')
|
cgen.genln(' load_so(live_library_name);')
|
||||||
cgen.genln(' pthread_t _thread_so;')
|
cgen.genln(' pthread_t _thread_so;')
|
||||||
cgen.genln(' pthread_create(&_thread_so , NULL, (void *)&reload_so, live_library_name);')
|
cgen.genln(' pthread_create(&_thread_so , NULL, (void *)&reload_so, live_library_name);')
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// windows:
|
// windows:
|
||||||
so_name := file_base + if v.pref.ccompiler == 'msvc' {'.dll'} else {'.so'}
|
so_name := file_base + if v.pref.ccompiler == 'msvc' { '.dll' } else { '.so' }
|
||||||
cgen.genln(' char *live_library_name = "$so_name";')
|
cgen.genln(' char *live_library_name = "$so_name";')
|
||||||
cgen.genln(' live_fn_mutex = CreateMutexA(0, 0, 0);')
|
cgen.genln(' live_fn_mutex = CreateMutexA(0, 0, 0);')
|
||||||
cgen.genln(' load_so(live_library_name);')
|
cgen.genln(' load_so(live_library_name);')
|
||||||
|
@ -70,7 +74,6 @@ fn (v &V) generate_hotcode_reloading_main_caller() {
|
||||||
|
|
||||||
fn (v &V) generate_hot_reload_code() {
|
fn (v &V) generate_hot_reload_code() {
|
||||||
mut cgen := v.cgen
|
mut cgen := v.cgen
|
||||||
|
|
||||||
// Hot code reloading
|
// Hot code reloading
|
||||||
if v.pref.is_live {
|
if v.pref.is_live {
|
||||||
mut file := os.realpath(v.dir)
|
mut file := os.realpath(v.dir)
|
||||||
|
@ -79,17 +82,14 @@ fn (v &V) generate_hot_reload_code() {
|
||||||
// Need to build .so file before building the live application
|
// Need to build .so file before building the live application
|
||||||
// The live app needs to load this .so file on initialization.
|
// The live app needs to load this .so file on initialization.
|
||||||
mut vexe := os.args[0]
|
mut vexe := os.args[0]
|
||||||
|
|
||||||
if os.user_os() == 'windows' {
|
if os.user_os() == 'windows' {
|
||||||
vexe = cescaped_path(vexe)
|
vexe = cescaped_path(vexe)
|
||||||
file = cescaped_path(file)
|
file = cescaped_path(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
mut msvc := ''
|
mut msvc := ''
|
||||||
if v.pref.ccompiler == 'msvc' {
|
if v.pref.ccompiler == 'msvc' {
|
||||||
msvc = '-cc msvc'
|
msvc = '-cc msvc'
|
||||||
}
|
}
|
||||||
|
|
||||||
so_debug_flag := if v.pref.is_debug { '-g' } else { '' }
|
so_debug_flag := if v.pref.is_debug { '-g' } else { '' }
|
||||||
cmd_compile_shared_library := '$vexe $msvc $so_debug_flag -o $file_base -solive -shared $file'
|
cmd_compile_shared_library := '$vexe $msvc $so_debug_flag -o $file_base -solive -shared $file'
|
||||||
if v.pref.show_c_cmd {
|
if v.pref.show_c_cmd {
|
||||||
|
@ -100,7 +100,6 @@ fn (v &V) generate_hot_reload_code() {
|
||||||
diff := time.ticks() - ticks
|
diff := time.ticks() - ticks
|
||||||
println('compiling shared library took $diff ms')
|
println('compiling shared library took $diff ms')
|
||||||
println('=========\n')
|
println('=========\n')
|
||||||
|
|
||||||
cgen.genln('
|
cgen.genln('
|
||||||
|
|
||||||
void lfnmutex_print(char *s){
|
void lfnmutex_print(char *s){
|
||||||
|
@ -111,7 +110,6 @@ void lfnmutex_print(char *s){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
')
|
')
|
||||||
|
|
||||||
if v.os != .windows {
|
if v.os != .windows {
|
||||||
cgen.genln('
|
cgen.genln('
|
||||||
void* live_lib=0;
|
void* live_lib=0;
|
||||||
|
@ -153,12 +151,10 @@ int load_so(byteptr path) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
')
|
')
|
||||||
|
|
||||||
for so_fn in cgen.so_fns {
|
for so_fn in cgen.so_fns {
|
||||||
cgen.genln('$so_fn = (void *)GetProcAddress(live_lib, "$so_fn"); ')
|
cgen.genln('$so_fn = (void *)GetProcAddress(live_lib, "$so_fn"); ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cgen.genln('return 1;
|
cgen.genln('return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,10 +214,10 @@ void reload_so() {
|
||||||
time__sleep_ms(100);
|
time__sleep_ms(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
' )
|
')
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.pref.is_so {
|
if v.pref.is_so {
|
||||||
cgen.genln(' int load_so(byteptr path) { return 0; }')
|
cgen.genln(' int load_so(byteptr path) { return 0; }')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -9,28 +8,27 @@ import (
|
||||||
os
|
os
|
||||||
filepath
|
filepath
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
.vh generation logic.
|
.vh generation logic.
|
||||||
.vh files contain only function signatures, consts, and types.
|
.vh files contain only function signatures, consts, and types.
|
||||||
They are used together with pre-compiled modules.
|
They are used together with pre-compiled modules.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
struct VhGen {
|
struct VhGen {
|
||||||
mut:
|
mut:
|
||||||
i int // token index
|
i int // token index
|
||||||
consts strings.Builder
|
consts strings.Builder
|
||||||
fns strings.Builder
|
fns strings.Builder
|
||||||
types strings.Builder
|
types strings.Builder
|
||||||
tokens []Token
|
tokens []Token
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `mod` == "vlib/os"
|
// `mod` == "vlib/os"
|
||||||
fn generate_vh(mod string) {
|
fn generate_vh(mod string) {
|
||||||
println('\n\n\n\nGenerating a V header file for module `$mod`')
|
println('\n\n\n\nGenerating a V header file for module `$mod`')
|
||||||
vexe := vexe_path()
|
vexe := vexe_path()
|
||||||
full_mod_path := filepath.join(os.dir(vexe), mod)
|
full_mod_path := filepath.join(os.dir(vexe),mod)
|
||||||
dir := if mod.starts_with('vlib') { '$compiler.v_modules_path${os.path_separator}$mod' } else { mod }
|
dir := if mod.starts_with('vlib') { '$compiler.v_modules_path${os.path_separator}$mod' } else { mod }
|
||||||
path := dir + '.vh'
|
path := dir + '.vh'
|
||||||
pdir := dir.all_before_last(os.path_separator)
|
pdir := dir.all_before_last(os.path_separator)
|
||||||
|
@ -38,32 +36,28 @@ fn generate_vh(mod string) {
|
||||||
os.mkdir_all(pdir)
|
os.mkdir_all(pdir)
|
||||||
// os.mkdir(os.realpath(dir)) or { panic(err) }
|
// os.mkdir(os.realpath(dir)) or { panic(err) }
|
||||||
}
|
}
|
||||||
mut out := os.create(path) or { panic(err) }
|
mut out := os.create(path)or{
|
||||||
mod_path := mod.replace("\\", "/")
|
panic(err)
|
||||||
|
}
|
||||||
|
mod_path := mod.replace('\\', '/')
|
||||||
out.writeln('// $mod_path module header\n')
|
out.writeln('// $mod_path module header\n')
|
||||||
mod_def := if mod_path.contains('/') { mod_path.all_after('/') } else { mod_path } // "os"
|
mod_def := if mod_path.contains('/') { mod_path.all_after('/') } else { mod_path } // "os"
|
||||||
out.writeln('module $mod_def\n')
|
out.writeln('module $mod_def\n')
|
||||||
// Consts
|
// Consts
|
||||||
println(full_mod_path)
|
println(full_mod_path)
|
||||||
vfiles := os.walk_ext(full_mod_path, '.v')
|
vfiles := os.walk_ext(full_mod_path, '.v')
|
||||||
//mut vfiles := os.ls(full_mod_path) or {
|
// mut vfiles := os.ls(full_mod_path) or {
|
||||||
//exit(1)
|
// exit(1)
|
||||||
//}
|
// }
|
||||||
filtered := vfiles.filter(it.ends_with('.v') && !it.ends_with('test.v') &&
|
filtered := vfiles.filter(it.ends_with('.v') && !it.ends_with('test.v') && !it.ends_with('_windows.v') && !it.ends_with('_win.v') && !it.ends_with('_lin.v') && !it.contains('${os.path_separator}examples') && !it.contains('_js.v') && !it.contains('_bare.v') && !it.contains('${os.path_separator}js')) // TODO merge once filter allows it
|
||||||
!it.ends_with('_windows.v') && !it.ends_with('_win.v') &&
|
// println('f:')
|
||||||
!it.ends_with('_lin.v') &&
|
// println(filtered)
|
||||||
!it.contains('${os.path_separator}examples') &&
|
|
||||||
!it.contains('_js.v') &&
|
|
||||||
!it.contains('_bare.v') &&
|
|
||||||
!it.contains('${os.path_separator}js')) // TODO merge once filter allows it
|
|
||||||
//println('f:')
|
|
||||||
//println(filtered)
|
|
||||||
mut v := new_v(['foo.v'])
|
mut v := new_v(['foo.v'])
|
||||||
//v.pref.generating_vh = true
|
// v.pref.generating_vh = true
|
||||||
mut g := VhGen{
|
mut g := VhGen{
|
||||||
consts : strings.new_builder(1000)
|
consts: strings.new_builder(1000)
|
||||||
fns : strings.new_builder(1000)
|
fns: strings.new_builder(1000)
|
||||||
types : strings.new_builder(1000)
|
types: strings.new_builder(1000)
|
||||||
}
|
}
|
||||||
for file in filtered {
|
for file in filtered {
|
||||||
mut p := v.new_parser_from_file(file)
|
mut p := v.new_parser_from_file(file)
|
||||||
|
@ -76,19 +70,23 @@ fn generate_vh(mod string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
match g.tokens[g.i].tok {
|
match g.tokens[g.i].tok {
|
||||||
.key_fn { g.generate_fn() }
|
.key_fn {
|
||||||
.key_const { g.generate_const() }
|
g.generate_fn()
|
||||||
.key_struct { g.generate_type() }
|
}
|
||||||
.key_type { g.generate_alias() }
|
.key_const {
|
||||||
else {}
|
g.generate_const()
|
||||||
}
|
}
|
||||||
|
.key_struct {
|
||||||
|
g.generate_type()
|
||||||
|
}
|
||||||
|
.key_type {
|
||||||
|
g.generate_alias()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result :=
|
result := g.types.str() + g.consts.str() + g.fns.str().replace('\n\n\n', '\n').replace('\n\n', '\n')
|
||||||
g.types.str() +
|
|
||||||
g.consts.str() +
|
|
||||||
g.fns.str().replace('\n\n\n', '\n').replace('\n\n', '\n')
|
|
||||||
|
|
||||||
out.writeln(result.replace('[ ] ', '[]').replace('? ', '?'))
|
out.writeln(result.replace('[ ] ', '[]').replace('? ', '?'))
|
||||||
out.close()
|
out.close()
|
||||||
}
|
}
|
||||||
|
@ -97,23 +95,21 @@ fn (g mut VhGen) generate_fn() {
|
||||||
if g.i >= g.tokens.len - 2 {
|
if g.i >= g.tokens.len - 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mut next := g.tokens[g.i+1]
|
mut next := g.tokens[g.i + 1]
|
||||||
if g.i > 0 && g.tokens[g.i-1].tok != .key_pub {
|
if g.i > 0 && g.tokens[g.i - 1].tok != .key_pub {
|
||||||
// Skip private fns
|
// Skip private fns
|
||||||
//return ''
|
// return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
if next.tok == .name && next.lit == 'C' {
|
if next.tok == .name && next.lit == 'C' {
|
||||||
//println('skipping C')
|
// println('skipping C')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//out.write('pub ')
|
// out.write('pub ')
|
||||||
mut tok := g.tokens[g.i]
|
mut tok := g.tokens[g.i]
|
||||||
for g.i < g.tokens.len - 1 && tok.tok != .lcbr {
|
for g.i < g.tokens.len - 1 && tok.tok != .lcbr {
|
||||||
next = g.tokens[g.i+1]
|
next = g.tokens[g.i + 1]
|
||||||
|
|
||||||
g.fns.write(tok.str())
|
g.fns.write(tok.str())
|
||||||
if tok.tok != .lpar && !(next.tok in [.comma, .rpar]) {
|
if tok.tok != .lpar && !(next.tok in [.comma, .rpar]) {
|
||||||
// No space after (), [], etc
|
// No space after (), [], etc
|
||||||
g.fns.write(' ')
|
g.fns.write(' ')
|
||||||
}
|
}
|
||||||
|
@ -121,22 +117,22 @@ fn (g mut VhGen) generate_fn() {
|
||||||
tok = g.tokens[g.i]
|
tok = g.tokens[g.i]
|
||||||
}
|
}
|
||||||
g.fns.writeln('')
|
g.fns.writeln('')
|
||||||
//g.i--
|
// g.i--
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut VhGen) generate_alias() {
|
fn (g mut VhGen) generate_alias() {
|
||||||
mut tok := g.tokens[g.i]
|
mut tok := g.tokens[g.i]
|
||||||
for g.i < g.tokens.len-1 {
|
for g.i < g.tokens.len - 1 {
|
||||||
g.types.write(tok.str())
|
g.types.write(tok.str())
|
||||||
g.types.write(' ')
|
g.types.write(' ')
|
||||||
if tok.line_nr != g.tokens[g.i+1].line_nr {
|
if tok.line_nr != g.tokens[g.i + 1].line_nr {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
g.i++
|
g.i++
|
||||||
tok = g.tokens[g.i]
|
tok = g.tokens[g.i]
|
||||||
}
|
}
|
||||||
g.types.writeln('\n')
|
g.types.writeln('\n')
|
||||||
//g.i--
|
// g.i--
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut VhGen) generate_const() {
|
fn (g mut VhGen) generate_const() {
|
||||||
|
@ -144,29 +140,30 @@ fn (g mut VhGen) generate_const() {
|
||||||
for g.i < g.tokens.len && tok.tok != .rpar {
|
for g.i < g.tokens.len && tok.tok != .rpar {
|
||||||
g.consts.write(tok.str())
|
g.consts.write(tok.str())
|
||||||
g.consts.write(' ')
|
g.consts.write(' ')
|
||||||
if g.tokens[g.i+2].tok == .assign {
|
if g.tokens[g.i + 2].tok == .assign {
|
||||||
g.consts.write('\n\t')
|
g.consts.write('\n\t')
|
||||||
}
|
}
|
||||||
g.i++
|
g.i++
|
||||||
tok = g.tokens[g.i]
|
tok = g.tokens[g.i]
|
||||||
}
|
}
|
||||||
g.consts.writeln('\n)')
|
g.consts.writeln('\n)')
|
||||||
//g.i--
|
// g.i--
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut VhGen) generate_type() {
|
fn (g mut VhGen) generate_type() {
|
||||||
//old := g.i
|
// old := g.i
|
||||||
mut tok := g.tokens[g.i]
|
mut tok := g.tokens[g.i]
|
||||||
for g.i < g.tokens.len && tok.tok != .rcbr {
|
for g.i < g.tokens.len && tok.tok != .rcbr {
|
||||||
g.types.write(tok.str())
|
g.types.write(tok.str())
|
||||||
g.types.write(' ')
|
g.types.write(' ')
|
||||||
if g.tokens[g.i+1].line_nr != g.tokens[g.i].line_nr {
|
if g.tokens[g.i + 1].line_nr != g.tokens[g.i].line_nr {
|
||||||
g.types.write('\n\t')
|
g.types.write('\n\t')
|
||||||
}
|
}
|
||||||
g.i++
|
g.i++
|
||||||
tok = g.tokens[g.i]
|
tok = g.tokens[g.i]
|
||||||
}
|
}
|
||||||
g.types.writeln('\n}')
|
g.types.writeln('\n}')
|
||||||
//g.i = old
|
// g.i = old
|
||||||
//g.i--
|
// g.i--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -10,15 +9,13 @@ import filepath
|
||||||
pub const (
|
pub const (
|
||||||
v_modules_path = os.home_dir() + '.vmodules'
|
v_modules_path = os.home_dir() + '.vmodules'
|
||||||
)
|
)
|
||||||
|
|
||||||
// Holds import information scoped to the parsed file
|
// Holds import information scoped to the parsed file
|
||||||
struct ImportTable {
|
struct ImportTable {
|
||||||
mut:
|
mut:
|
||||||
imports map[string]string // alias => module
|
imports map[string]string // alias => module
|
||||||
used_imports []string // alias
|
used_imports []string // alias
|
||||||
import_tok_idx map[string]int // module => idx
|
import_tok_idx map[string]int // module => idx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once we have a module format we can read from module file instead
|
// Once we have a module format we can read from module file instead
|
||||||
// this is not optimal
|
// this is not optimal
|
||||||
fn (table &Table) qualify_module(mod string, file_path string) string {
|
fn (table &Table) qualify_module(mod string, file_path string) string {
|
||||||
|
@ -26,7 +23,7 @@ fn (table &Table) qualify_module(mod string, file_path string) string {
|
||||||
if m.contains('.') && m.contains(mod) {
|
if m.contains('.') && m.contains(mod) {
|
||||||
m_parts := m.split('.')
|
m_parts := m.split('.')
|
||||||
m_path := m_parts.join(os.path_separator)
|
m_path := m_parts.join(os.path_separator)
|
||||||
if mod == m_parts[m_parts.len-1] && file_path.contains(m_path) {
|
if mod == m_parts[m_parts.len - 1] && file_path.contains(m_path) {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +33,7 @@ fn (table &Table) qualify_module(mod string, file_path string) string {
|
||||||
|
|
||||||
fn new_import_table() ImportTable {
|
fn new_import_table() ImportTable {
|
||||||
return ImportTable{
|
return ImportTable{
|
||||||
imports: map[string]string
|
imports: map[string]string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +51,9 @@ fn (p mut Parser) register_import_alias(alias string, mod string, tok_idx int) {
|
||||||
mod_parts := mod.split('.')
|
mod_parts := mod.split('.')
|
||||||
mut internal_mod_parts := []string
|
mut internal_mod_parts := []string
|
||||||
for part in mod_parts {
|
for part in mod_parts {
|
||||||
if part == 'internal' { break }
|
if part == 'internal' {
|
||||||
|
break
|
||||||
|
}
|
||||||
internal_mod_parts << part
|
internal_mod_parts << part
|
||||||
}
|
}
|
||||||
internal_parent := internal_mod_parts.join('.')
|
internal_parent := internal_mod_parts.join('.')
|
||||||
|
@ -121,7 +120,7 @@ pub fn (v &V) resolve_deps() &DepGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
// graph of all imported modules
|
// graph of all imported modules
|
||||||
pub fn(v &V) import_graph() &DepGraph {
|
pub fn (v &V) import_graph() &DepGraph {
|
||||||
mut graph := new_dep_graph()
|
mut graph := new_dep_graph()
|
||||||
for p in v.parsers {
|
for p in v.parsers {
|
||||||
mut deps := []string
|
mut deps := []string
|
||||||
|
@ -134,7 +133,7 @@ pub fn(v &V) import_graph() &DepGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get ordered imports (module speficic dag method)
|
// get ordered imports (module speficic dag method)
|
||||||
pub fn(graph &DepGraph) imports() []string {
|
pub fn (graph &DepGraph) imports() []string {
|
||||||
mut mods := []string
|
mut mods := []string
|
||||||
for node in graph.nodes {
|
for node in graph.nodes {
|
||||||
mods << node.name
|
mods << node.name
|
||||||
|
@ -142,7 +141,8 @@ pub fn(graph &DepGraph) imports() []string {
|
||||||
return mods
|
return mods
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline] fn (v &V) module_path(mod string) string {
|
[inline]
|
||||||
|
fn (v &V) module_path(mod string) string {
|
||||||
// submodule support
|
// submodule support
|
||||||
return mod.replace('.', os.path_separator)
|
return mod.replace('.', os.path_separator)
|
||||||
}
|
}
|
||||||
|
@ -150,33 +150,30 @@ pub fn(graph &DepGraph) imports() []string {
|
||||||
// 'strings' => 'VROOT/vlib/strings'
|
// 'strings' => 'VROOT/vlib/strings'
|
||||||
// 'installed_mod' => '~/.vmodules/installed_mod'
|
// 'installed_mod' => '~/.vmodules/installed_mod'
|
||||||
// 'local_mod' => '/path/to/current/dir/local_mod'
|
// 'local_mod' => '/path/to/current/dir/local_mod'
|
||||||
|
fn (v mut V) set_module_lookup_paths() {
|
||||||
fn (v mut V) set_module_lookup_paths(){
|
mlookup_path := if v.pref.vpath.len > 0 { v.pref.vpath } else { v_modules_path }
|
||||||
mlookup_path := if v.pref.vpath.len>0{ v.pref.vpath }else{ v_modules_path }
|
|
||||||
// Module search order:
|
// Module search order:
|
||||||
// 0) V test files are very commonly located right inside the folder of the
|
// 0) V test files are very commonly located right inside the folder of the
|
||||||
// module, which they test. Adding the parent folder of the module folder
|
// module, which they test. Adding the parent folder of the module folder
|
||||||
// with the _test.v files, *guarantees* that the tested module can be found
|
// with the _test.v files, *guarantees* that the tested module can be found
|
||||||
// without needing to set custom options/flags.
|
// without needing to set custom options/flags.
|
||||||
|
|
||||||
// 1) search in the *same* directory, as the compiled final v program source
|
// 1) search in the *same* directory, as the compiled final v program source
|
||||||
// (i.e. the . in `v .` or file.v in `v file.v`)
|
// (i.e. the . in `v .` or file.v in `v file.v`)
|
||||||
// 2) search in the modules/ in the same directory.
|
// 2) search in the modules/ in the same directory.
|
||||||
// 3) search in vlib/
|
// 3) search in vlib/
|
||||||
// 4.1) search in -vpath (if given)
|
// 4.1) search in -vpath (if given)
|
||||||
// 4.2) search in ~/.vmodules/ (i.e. modules installed with vpm) (no -vpath)
|
// 4.2) search in ~/.vmodules/ (i.e. modules installed with vpm) (no -vpath)
|
||||||
v.module_lookup_paths = []
|
v.module_lookup_paths = []
|
||||||
if v.pref.is_test {
|
if v.pref.is_test {
|
||||||
v.module_lookup_paths << os.basedir(v.compiled_dir) // pdir of _test.v
|
v.module_lookup_paths << os.basedir(v.compiled_dir) // pdir of _test.v
|
||||||
}
|
}
|
||||||
v.module_lookup_paths << v.compiled_dir
|
v.module_lookup_paths << v.compiled_dir
|
||||||
v.module_lookup_paths << filepath.join(v.compiled_dir, 'modules')
|
v.module_lookup_paths << filepath.join(v.compiled_dir,'modules')
|
||||||
v.module_lookup_paths << v.pref.vlib_path
|
v.module_lookup_paths << v.pref.vlib_path
|
||||||
v.module_lookup_paths << mlookup_path
|
v.module_lookup_paths << mlookup_path
|
||||||
if v.pref.user_mod_path.len > 0 {
|
if v.pref.user_mod_path.len > 0 {
|
||||||
v.module_lookup_paths << v.pref.user_mod_path
|
v.module_lookup_paths << v.pref.user_mod_path
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
v.log('v.module_lookup_paths: $v.module_lookup_paths')
|
v.log('v.module_lookup_paths: $v.module_lookup_paths')
|
||||||
}
|
}
|
||||||
|
@ -185,20 +182,27 @@ fn (v mut V) set_module_lookup_paths(){
|
||||||
fn (v &V) find_module_path(mod string) ?string {
|
fn (v &V) find_module_path(mod string) ?string {
|
||||||
mod_path := v.module_path(mod)
|
mod_path := v.module_path(mod)
|
||||||
for lookup_path in v.module_lookup_paths {
|
for lookup_path in v.module_lookup_paths {
|
||||||
try_path := filepath.join(lookup_path, mod_path)
|
try_path := filepath.join(lookup_path,mod_path)
|
||||||
if v.pref.is_verbose { println(' >> trying to find $mod in $try_path ...') }
|
if v.pref.is_verbose {
|
||||||
|
println(' >> trying to find $mod in $try_path ...')
|
||||||
|
}
|
||||||
if os.is_dir(try_path) {
|
if os.is_dir(try_path) {
|
||||||
if v.pref.is_verbose { println(' << found $try_path .') }
|
if v.pref.is_verbose {
|
||||||
return try_path
|
println(' << found $try_path .')
|
||||||
|
}
|
||||||
|
return try_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error('module "$mod" not found')
|
return error('module "$mod" not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline] fn mod_gen_name(mod string) string {
|
[inline]
|
||||||
|
fn mod_gen_name(mod string) string {
|
||||||
return mod.replace('.', '_dot_')
|
return mod.replace('.', '_dot_')
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline] fn mod_gen_name_rev(mod string) string {
|
[inline]
|
||||||
|
fn mod_gen_name_rev(mod string) string {
|
||||||
return mod.replace('_dot_', '.')
|
return mod.replace('_dot_', '.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,27 +3,22 @@ module compiler
|
||||||
import os
|
import os
|
||||||
|
|
||||||
#flag windows -l shell32
|
#flag windows -l shell32
|
||||||
#flag windows -l dbghelp
|
#flag windows -l dbghelp // RegOpenKeyExW etc
|
||||||
// RegOpenKeyExW etc
|
|
||||||
#flag windows -l advapi32
|
#flag windows -l advapi32
|
||||||
|
|
||||||
struct MsvcResult {
|
struct MsvcResult {
|
||||||
full_cl_exe_path string
|
full_cl_exe_path string
|
||||||
exe_path string
|
exe_path string
|
||||||
|
um_lib_path string
|
||||||
um_lib_path string
|
ucrt_lib_path string
|
||||||
ucrt_lib_path string
|
vs_lib_path string
|
||||||
vs_lib_path string
|
um_include_path string
|
||||||
|
ucrt_include_path string
|
||||||
um_include_path string
|
vs_include_path string
|
||||||
ucrt_include_path string
|
|
||||||
vs_include_path string
|
|
||||||
shared_include_path string
|
shared_include_path string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mimics a HKEY
|
// Mimics a HKEY
|
||||||
type RegKey voidptr
|
type RegKey voidptr
|
||||||
|
|
||||||
// Taken from the windows SDK
|
// Taken from the windows SDK
|
||||||
const (
|
const (
|
||||||
HKEY_LOCAL_MACHINE = RegKey(0x80000002)
|
HKEY_LOCAL_MACHINE = RegKey(0x80000002)
|
||||||
|
@ -31,39 +26,30 @@ const (
|
||||||
KEY_WOW64_32KEY = (0x0200)
|
KEY_WOW64_32KEY = (0x0200)
|
||||||
KEY_ENUMERATE_SUB_KEYS = (0x0008)
|
KEY_ENUMERATE_SUB_KEYS = (0x0008)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Given a root key look for one of the subkeys in 'versions' and get the path
|
// Given a root key look for one of the subkeys in 'versions' and get the path
|
||||||
fn find_windows_kit_internal(key RegKey, versions []string) ?string {
|
fn find_windows_kit_internal(key RegKey, versions []string) ?string {
|
||||||
$if windows {
|
$if windows {
|
||||||
for version in versions {
|
for version in versions {
|
||||||
required_bytes := 0 // TODO mut
|
required_bytes := 0 // TODO mut
|
||||||
result := C.RegQueryValueEx(key, version.to_wide(), 0, 0, 0, &required_bytes)
|
result := C.RegQueryValueEx(key, version.to_wide(), 0, 0, 0, &required_bytes)
|
||||||
|
|
||||||
length := required_bytes / 2
|
length := required_bytes / 2
|
||||||
|
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc_length := (required_bytes + 2)
|
alloc_length := (required_bytes + 2)
|
||||||
|
|
||||||
mut value := &u16(malloc(alloc_length))
|
mut value := &u16(malloc(alloc_length))
|
||||||
if isnil(value) {
|
if isnil(value) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
result2 := C.RegQueryValueEx(key, version.to_wide(), 0, 0, value, &alloc_length)
|
result2 := C.RegQueryValueEx(key, version.to_wide(), 0, 0, value, &alloc_length)
|
||||||
|
|
||||||
if result2 != 0 {
|
if result2 != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// We might need to manually null terminate this thing
|
// We might need to manually null terminate this thing
|
||||||
// So just make sure that we do that
|
// So just make sure that we do that
|
||||||
if (value[length - 1] != u16(0)) {
|
if (value[length - 1] != u16(0)) {
|
||||||
value[length] = u16(0)
|
value[length] = u16(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return string_from_wide(value)
|
return string_from_wide(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,11 +57,10 @@ fn find_windows_kit_internal(key RegKey, versions []string) ?string {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WindowsKit {
|
struct WindowsKit {
|
||||||
um_lib_path string
|
um_lib_path string
|
||||||
ucrt_lib_path string
|
ucrt_lib_path string
|
||||||
|
um_include_path string
|
||||||
um_include_path string
|
ucrt_include_path string
|
||||||
ucrt_include_path string
|
|
||||||
shared_include_path string
|
shared_include_path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,45 +68,38 @@ struct WindowsKit {
|
||||||
fn find_windows_kit_root(host_arch string) ?WindowsKit {
|
fn find_windows_kit_root(host_arch string) ?WindowsKit {
|
||||||
$if windows {
|
$if windows {
|
||||||
root_key := RegKey(0)
|
root_key := RegKey(0)
|
||||||
rc := C.RegOpenKeyEx(
|
rc := C.RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots'.to_wide(), 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &root_key)
|
||||||
HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots'.to_wide(), 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &root_key)
|
defer {
|
||||||
|
C.RegCloseKey(root_key)
|
||||||
defer {C.RegCloseKey(root_key)}
|
}
|
||||||
|
|
||||||
if rc != 0 {
|
if rc != 0 {
|
||||||
return error('Unable to open root key')
|
return error('Unable to open root key')
|
||||||
}
|
}
|
||||||
// Try and find win10 kit
|
// Try and find win10 kit
|
||||||
kit_root := find_windows_kit_internal(root_key, ['KitsRoot10', 'KitsRoot81']) or {
|
kit_root := find_windows_kit_internal(root_key, ['KitsRoot10', 'KitsRoot81'])or{
|
||||||
return error('Unable to find a windows kit')
|
return error('Unable to find a windows kit')
|
||||||
}
|
}
|
||||||
|
|
||||||
kit_lib := kit_root + 'Lib'
|
kit_lib := kit_root + 'Lib'
|
||||||
|
|
||||||
// println(kit_lib)
|
// println(kit_lib)
|
||||||
|
files := os.ls(kit_lib)or{
|
||||||
files := os.ls(kit_lib) or { panic(err) }
|
panic(err)
|
||||||
|
}
|
||||||
mut highest_path := ''
|
mut highest_path := ''
|
||||||
mut highest_int := 0
|
mut highest_int := 0
|
||||||
for f in files {
|
for f in files {
|
||||||
no_dot := f.replace('.', '')
|
no_dot := f.replace('.', '')
|
||||||
v_int := no_dot.int()
|
v_int := no_dot.int()
|
||||||
|
|
||||||
if v_int > highest_int {
|
if v_int > highest_int {
|
||||||
highest_int = v_int
|
highest_int = v_int
|
||||||
highest_path = f
|
highest_path = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kit_lib_highest := kit_lib + '\\$highest_path'
|
kit_lib_highest := kit_lib + '\\$highest_path'
|
||||||
kit_include_highest := kit_lib_highest.replace('Lib', 'Include')
|
kit_include_highest := kit_lib_highest.replace('Lib', 'Include')
|
||||||
|
|
||||||
// println('$kit_lib_highest $kit_include_highest')
|
// println('$kit_lib_highest $kit_include_highest')
|
||||||
|
return WindowsKit{
|
||||||
return WindowsKit {
|
|
||||||
um_lib_path: kit_lib_highest + '\\um\\$host_arch'
|
um_lib_path: kit_lib_highest + '\\um\\$host_arch'
|
||||||
ucrt_lib_path: kit_lib_highest + '\\ucrt\\$host_arch'
|
ucrt_lib_path: kit_lib_highest + '\\ucrt\\$host_arch'
|
||||||
|
|
||||||
um_include_path: kit_include_highest + '\\um'
|
um_include_path: kit_include_highest + '\\um'
|
||||||
ucrt_include_path: kit_include_highest + '\\ucrt'
|
ucrt_include_path: kit_include_highest + '\\ucrt'
|
||||||
shared_include_path: kit_include_highest + '\\shared'
|
shared_include_path: kit_include_highest + '\\shared'
|
||||||
|
@ -132,8 +110,8 @@ fn find_windows_kit_root(host_arch string) ?WindowsKit {
|
||||||
|
|
||||||
struct VsInstallation {
|
struct VsInstallation {
|
||||||
include_path string
|
include_path string
|
||||||
lib_path string
|
lib_path string
|
||||||
exe_path string
|
exe_path string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_vs(vswhere_dir string, host_arch string) ?VsInstallation {
|
fn find_vs(vswhere_dir string, host_arch string) ?VsInstallation {
|
||||||
|
@ -144,40 +122,27 @@ fn find_vs(vswhere_dir string, host_arch string) ?VsInstallation {
|
||||||
// VSWhere is guaranteed to be installed at this location now
|
// VSWhere is guaranteed to be installed at this location now
|
||||||
// If its not there then end user needs to update their visual studio
|
// If its not there then end user needs to update their visual studio
|
||||||
// installation!
|
// installation!
|
||||||
|
res := os.exec('"$vswhere_dir\\Microsoft Visual Studio\\Installer\\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath')or{
|
||||||
res := os.exec('"$vswhere_dir\\Microsoft Visual Studio\\Installer\\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath') or {
|
|
||||||
return error(err)
|
return error(err)
|
||||||
}
|
}
|
||||||
// println('res: "$res"')
|
// println('res: "$res"')
|
||||||
|
version := os.read_file('$res.output\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt')or{
|
||||||
version := os.read_file('$res.output\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt') or {
|
|
||||||
println('Unable to find msvc version')
|
println('Unable to find msvc version')
|
||||||
return error('Unable to find vs installation')
|
return error('Unable to find vs installation')
|
||||||
}
|
}
|
||||||
|
|
||||||
// println('version: $version')
|
// println('version: $version')
|
||||||
|
v := if version.ends_with('\n') { version[..version.len - 2] } else { version }
|
||||||
v := if version.ends_with('\n') {
|
|
||||||
version[..version.len - 2]
|
|
||||||
} else {
|
|
||||||
version
|
|
||||||
}
|
|
||||||
|
|
||||||
lib_path := '$res.output\\VC\\Tools\\MSVC\\$v\\lib\\$host_arch'
|
lib_path := '$res.output\\VC\\Tools\\MSVC\\$v\\lib\\$host_arch'
|
||||||
include_path := '$res.output\\VC\\Tools\\MSVC\\$v\\include'
|
include_path := '$res.output\\VC\\Tools\\MSVC\\$v\\include'
|
||||||
|
|
||||||
if os.exists('$lib_path\\vcruntime.lib') {
|
if os.exists('$lib_path\\vcruntime.lib') {
|
||||||
p := '$res.output\\VC\\Tools\\MSVC\\$v\\bin\\Host$host_arch\\$host_arch'
|
p := '$res.output\\VC\\Tools\\MSVC\\$v\\bin\\Host$host_arch\\$host_arch'
|
||||||
|
|
||||||
// println('$lib_path $include_path')
|
// println('$lib_path $include_path')
|
||||||
|
|
||||||
return VsInstallation{
|
return VsInstallation{
|
||||||
exe_path: p
|
exe_path: p
|
||||||
lib_path: lib_path
|
lib_path: lib_path
|
||||||
include_path: include_path
|
include_path: include_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println('Unable to find vs installation (attempted to use lib path "$lib_path")')
|
println('Unable to find vs installation (attempted to use lib path "$lib_path")')
|
||||||
return error('Unable to find vs exe folder')
|
return error('Unable to find vs exe folder')
|
||||||
}
|
}
|
||||||
|
@ -185,45 +150,33 @@ fn find_vs(vswhere_dir string, host_arch string) ?VsInstallation {
|
||||||
fn find_msvc() ?MsvcResult {
|
fn find_msvc() ?MsvcResult {
|
||||||
$if windows {
|
$if windows {
|
||||||
processor_architecture := os.getenv('PROCESSOR_ARCHITECTURE')
|
processor_architecture := os.getenv('PROCESSOR_ARCHITECTURE')
|
||||||
vswhere_dir := if processor_architecture == 'x86' {
|
vswhere_dir := if processor_architecture == 'x86' { '%ProgramFiles%' } else { '%ProgramFiles(x86)%' }
|
||||||
'%ProgramFiles%'
|
host_arch := if processor_architecture == 'x86' { 'X86' } else { 'X64' }
|
||||||
} else {
|
wk := find_windows_kit_root(host_arch)or{
|
||||||
'%ProgramFiles(x86)%'
|
|
||||||
}
|
|
||||||
host_arch := if processor_architecture == 'x86' {
|
|
||||||
'X86'
|
|
||||||
} else {
|
|
||||||
'X64'
|
|
||||||
}
|
|
||||||
wk := find_windows_kit_root(host_arch) or {
|
|
||||||
return error('Unable to find windows sdk')
|
return error('Unable to find windows sdk')
|
||||||
}
|
}
|
||||||
vs := find_vs(vswhere_dir, host_arch) or {
|
vs := find_vs(vswhere_dir, host_arch)or{
|
||||||
return error('Unable to find visual studio')
|
return error('Unable to find visual studio')
|
||||||
}
|
}
|
||||||
|
return MsvcResult{
|
||||||
return MsvcResult {
|
full_cl_exe_path: os.realpath(vs.exe_path + os.path_separator + 'cl.exe')
|
||||||
full_cl_exe_path: os.realpath( vs.exe_path + os.path_separator + 'cl.exe' )
|
exe_path: vs.exe_path
|
||||||
exe_path: vs.exe_path,
|
um_lib_path: wk.um_lib_path
|
||||||
|
ucrt_lib_path: wk.ucrt_lib_path
|
||||||
um_lib_path: wk.um_lib_path,
|
vs_lib_path: vs.lib_path
|
||||||
ucrt_lib_path: wk.ucrt_lib_path,
|
um_include_path: wk.um_include_path
|
||||||
vs_lib_path: vs.lib_path,
|
ucrt_include_path: wk.ucrt_include_path
|
||||||
|
vs_include_path: vs.include_path
|
||||||
um_include_path: wk.um_include_path,
|
shared_include_path: wk.shared_include_path
|
||||||
ucrt_include_path: wk.ucrt_include_path,
|
|
||||||
vs_include_path: vs.include_path,
|
|
||||||
shared_include_path: wk.shared_include_path,
|
|
||||||
}
|
}
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
verror('Cannot find msvc on this OS')
|
verror('Cannot find msvc on this OS')
|
||||||
return error('msvc not found')
|
return error('msvc not found')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (v mut V) cc_msvc() {
|
pub fn (v mut V) cc_msvc() {
|
||||||
r := find_msvc() or {
|
r := find_msvc()or{
|
||||||
// TODO: code reuse
|
// TODO: code reuse
|
||||||
if !v.pref.is_keep_c && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' {
|
if !v.pref.is_keep_c && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' {
|
||||||
os.rm(v.out_name_c)
|
os.rm(v.out_name_c)
|
||||||
|
@ -231,41 +184,35 @@ pub fn (v mut V) cc_msvc() {
|
||||||
verror('Cannot find MSVC on this OS')
|
verror('Cannot find MSVC on this OS')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
out_name_obj := os.realpath(v.out_name_c + '.obj')
|
||||||
out_name_obj := os.realpath( v.out_name_c + '.obj' )
|
|
||||||
|
|
||||||
// Default arguments
|
// Default arguments
|
||||||
|
|
||||||
// volatile:ms enables atomic volatile (gcc _Atomic)
|
// volatile:ms enables atomic volatile (gcc _Atomic)
|
||||||
// -w: no warnings
|
// -w: no warnings
|
||||||
// 2 unicode defines
|
// 2 unicode defines
|
||||||
// /Fo sets the object file name - needed so we can clean up after ourselves properly
|
// /Fo sets the object file name - needed so we can clean up after ourselves properly
|
||||||
mut a := ['-w', '/we4013', '/volatile:ms', '/Fo"$out_name_obj"']
|
mut a := ['-w', '/we4013', '/volatile:ms', '/Fo"$out_name_obj"']
|
||||||
|
|
||||||
if v.pref.is_prod {
|
if v.pref.is_prod {
|
||||||
a << '/O2'
|
a << '/O2'
|
||||||
a << '/MD'
|
a << '/MD'
|
||||||
a << '/Zi'
|
a << '/Zi'
|
||||||
a << '/DNDEBUG'
|
a << '/DNDEBUG'
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
a << '/Zi'
|
a << '/Zi'
|
||||||
a << '/MDd'
|
a << '/MDd'
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.pref.is_so {
|
if v.pref.is_so {
|
||||||
if !v.out_name.ends_with('.dll') {
|
if !v.out_name.ends_with('.dll') {
|
||||||
v.out_name = v.out_name + '.dll'
|
v.out_name = v.out_name + '.dll'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build dll
|
// Build dll
|
||||||
a << '/LD'
|
a << '/LD'
|
||||||
} else if !v.out_name.ends_with('.exe') {
|
}
|
||||||
|
else if !v.out_name.ends_with('.exe') {
|
||||||
v.out_name = v.out_name + '.exe'
|
v.out_name = v.out_name + '.exe'
|
||||||
}
|
}
|
||||||
|
v.out_name = os.realpath(v.out_name)
|
||||||
v.out_name = os.realpath( v.out_name )
|
// alibs := []string // builtin.o os.o http.o etc
|
||||||
|
|
||||||
//alibs := []string // builtin.o os.o http.o etc
|
|
||||||
if v.pref.build_mode == .build_module {
|
if v.pref.build_mode == .build_module {
|
||||||
// Compile only
|
// Compile only
|
||||||
a << '/c'
|
a << '/c'
|
||||||
|
@ -286,52 +233,30 @@ pub fn (v mut V) cc_msvc() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.pref.sanitize {
|
if v.pref.sanitize {
|
||||||
println('Sanitize not supported on msvc.')
|
println('Sanitize not supported on msvc.')
|
||||||
}
|
}
|
||||||
|
|
||||||
// The C file we are compiling
|
// The C file we are compiling
|
||||||
//a << '"$TmpPath/$v.out_name_c"'
|
// a << '"$TmpPath/$v.out_name_c"'
|
||||||
a << '"' + os.realpath( v.out_name_c ) + '"'
|
a << '"' + os.realpath(v.out_name_c) + '"'
|
||||||
|
|
||||||
// Emily:
|
// Emily:
|
||||||
// Not all of these are needed (but the compiler should discard them if they are not used)
|
// Not all of these are needed (but the compiler should discard them if they are not used)
|
||||||
// these are the defaults used by msbuild and visual studio
|
// these are the defaults used by msbuild and visual studio
|
||||||
mut real_libs := [
|
mut real_libs := ['kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib', 'comdlg32.lib', 'advapi32.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'odbc32.lib', 'odbccp32.lib']
|
||||||
'kernel32.lib',
|
|
||||||
'user32.lib',
|
|
||||||
'gdi32.lib',
|
|
||||||
'winspool.lib',
|
|
||||||
'comdlg32.lib',
|
|
||||||
'advapi32.lib',
|
|
||||||
'shell32.lib',
|
|
||||||
'ole32.lib',
|
|
||||||
'oleaut32.lib',
|
|
||||||
'uuid.lib',
|
|
||||||
'odbc32.lib',
|
|
||||||
'odbccp32.lib'
|
|
||||||
]
|
|
||||||
|
|
||||||
sflags := v.get_os_cflags().msvc_string_flags()
|
sflags := v.get_os_cflags().msvc_string_flags()
|
||||||
real_libs << sflags.real_libs
|
real_libs << sflags.real_libs
|
||||||
inc_paths := sflags.inc_paths
|
inc_paths := sflags.inc_paths
|
||||||
lib_paths := sflags.lib_paths
|
lib_paths := sflags.lib_paths
|
||||||
other_flags := sflags.other_flags
|
other_flags := sflags.other_flags
|
||||||
|
|
||||||
// Include the base paths
|
// Include the base paths
|
||||||
a << '-I "$r.ucrt_include_path"'
|
a << '-I "$r.ucrt_include_path"'
|
||||||
a << '-I "$r.vs_include_path"'
|
a << '-I "$r.vs_include_path"'
|
||||||
a << '-I "$r.um_include_path"'
|
a << '-I "$r.um_include_path"'
|
||||||
a << '-I "$r.shared_include_path"'
|
a << '-I "$r.shared_include_path"'
|
||||||
|
|
||||||
a << inc_paths
|
a << inc_paths
|
||||||
|
|
||||||
a << other_flags
|
a << other_flags
|
||||||
|
|
||||||
// Libs are passed to cl.exe which passes them to the linker
|
// Libs are passed to cl.exe which passes them to the linker
|
||||||
a << real_libs.join(' ')
|
a << real_libs.join(' ')
|
||||||
|
|
||||||
a << '/link'
|
a << '/link'
|
||||||
a << '/NOLOGO'
|
a << '/NOLOGO'
|
||||||
a << '/OUT:"$v.out_name"'
|
a << '/OUT:"$v.out_name"'
|
||||||
|
@ -339,17 +264,13 @@ pub fn (v mut V) cc_msvc() {
|
||||||
a << '/LIBPATH:"$r.um_lib_path"'
|
a << '/LIBPATH:"$r.um_lib_path"'
|
||||||
a << '/LIBPATH:"$r.vs_lib_path"'
|
a << '/LIBPATH:"$r.vs_lib_path"'
|
||||||
a << '/DEBUG:FULL' // required for prod builds to generate PDB
|
a << '/DEBUG:FULL' // required for prod builds to generate PDB
|
||||||
|
|
||||||
if v.pref.is_prod {
|
if v.pref.is_prod {
|
||||||
a << '/INCREMENTAL:NO' // Disable incremental linking
|
a << '/INCREMENTAL:NO' // Disable incremental linking
|
||||||
a << '/OPT:REF'
|
a << '/OPT:REF'
|
||||||
a << '/OPT:ICF'
|
a << '/OPT:ICF'
|
||||||
}
|
}
|
||||||
|
|
||||||
a << lib_paths
|
a << lib_paths
|
||||||
|
|
||||||
args := a.join(' ')
|
args := a.join(' ')
|
||||||
|
|
||||||
cmd := '"$r.full_cl_exe_path" $args'
|
cmd := '"$r.full_cl_exe_path" $args'
|
||||||
// It is hard to see it at first, but the quotes above ARE balanced :-| ...
|
// It is hard to see it at first, but the quotes above ARE balanced :-| ...
|
||||||
// Also the double quotes at the start ARE needed.
|
// Also the double quotes at the start ARE needed.
|
||||||
|
@ -358,10 +279,8 @@ pub fn (v mut V) cc_msvc() {
|
||||||
println(cmd)
|
println(cmd)
|
||||||
println('==========\n')
|
println('==========\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
// println('$cmd')
|
// println('$cmd')
|
||||||
|
res := os.exec(cmd)or{
|
||||||
res := os.exec(cmd) or {
|
|
||||||
println(err)
|
println(err)
|
||||||
verror('msvc error')
|
verror('msvc error')
|
||||||
return
|
return
|
||||||
|
@ -371,51 +290,44 @@ pub fn (v mut V) cc_msvc() {
|
||||||
}
|
}
|
||||||
// println(res)
|
// println(res)
|
||||||
// println('C OUTPUT:')
|
// println('C OUTPUT:')
|
||||||
|
|
||||||
if !v.pref.is_keep_c && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' {
|
if !v.pref.is_keep_c && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' {
|
||||||
os.rm(v.out_name_c)
|
os.rm(v.out_name_c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always remove the object file - it is completely unnecessary
|
// Always remove the object file - it is completely unnecessary
|
||||||
os.rm(out_name_obj)
|
os.rm(out_name_obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_thirdparty_obj_file_with_msvc(path string, moduleflags []CFlag) {
|
fn build_thirdparty_obj_file_with_msvc(path string, moduleflags []CFlag) {
|
||||||
msvc := find_msvc() or {
|
msvc := find_msvc()or{
|
||||||
println('Could not find visual studio')
|
println('Could not find visual studio')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// msvc expects .obj not .o
|
// msvc expects .obj not .o
|
||||||
mut obj_path := '${path}bj'
|
mut obj_path := '${path}bj'
|
||||||
|
|
||||||
obj_path = os.realpath(obj_path)
|
obj_path = os.realpath(obj_path)
|
||||||
|
|
||||||
if os.exists(obj_path) {
|
if os.exists(obj_path) {
|
||||||
println('$obj_path already build.')
|
println('$obj_path already build.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
println('$obj_path not found, building it (with msvc)...')
|
println('$obj_path not found, building it (with msvc)...')
|
||||||
parent := os.dir(obj_path)
|
parent := os.dir(obj_path)
|
||||||
files := os.ls(parent) or { panic(err) }
|
files := os.ls(parent)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
mut cfiles := ''
|
mut cfiles := ''
|
||||||
for file in files {
|
for file in files {
|
||||||
if file.ends_with('.c') {
|
if file.ends_with('.c') {
|
||||||
cfiles += '"' + os.realpath( parent + os.path_separator + file ) + '" '
|
cfiles += '"' + os.realpath(parent + os.path_separator + file) + '" '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
include_string := '-I "$msvc.ucrt_include_path" -I "$msvc.vs_include_path" -I "$msvc.um_include_path" -I "$msvc.shared_include_path"'
|
include_string := '-I "$msvc.ucrt_include_path" -I "$msvc.vs_include_path" -I "$msvc.um_include_path" -I "$msvc.shared_include_path"'
|
||||||
|
// println('cfiles: $cfiles')
|
||||||
//println('cfiles: $cfiles')
|
|
||||||
|
|
||||||
btarget := moduleflags.c_options_before_target_msvc()
|
btarget := moduleflags.c_options_before_target_msvc()
|
||||||
atarget := moduleflags.c_options_after_target_msvc()
|
atarget := moduleflags.c_options_after_target_msvc()
|
||||||
cmd := '"$msvc.full_cl_exe_path" /volatile:ms /Zi /DNDEBUG $include_string /c $btarget $cfiles $atarget /Fo"$obj_path"'
|
cmd := '"$msvc.full_cl_exe_path" /volatile:ms /Zi /DNDEBUG $include_string /c $btarget $cfiles $atarget /Fo"$obj_path"'
|
||||||
//NB: the quotes above ARE balanced.
|
// NB: the quotes above ARE balanced.
|
||||||
println('thirdparty cmd line: $cmd')
|
println('thirdparty cmd line: $cmd')
|
||||||
res := os.exec(cmd) or {
|
res := os.exec(cmd)or{
|
||||||
println('msvc: failed thirdparty object build cmd: $cmd')
|
println('msvc: failed thirdparty object build cmd: $cmd')
|
||||||
verror(err)
|
verror(err)
|
||||||
return
|
return
|
||||||
|
@ -428,12 +340,11 @@ fn build_thirdparty_obj_file_with_msvc(path string, moduleflags []CFlag) {
|
||||||
println(res.output)
|
println(res.output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct MsvcStringFlags {
|
struct MsvcStringFlags {
|
||||||
mut:
|
mut:
|
||||||
real_libs []string
|
real_libs []string
|
||||||
inc_paths []string
|
inc_paths []string
|
||||||
lib_paths []string
|
lib_paths []string
|
||||||
other_flags []string
|
other_flags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,9 +352,9 @@ fn (cflags []CFlag) msvc_string_flags() MsvcStringFlags {
|
||||||
mut real_libs := []string
|
mut real_libs := []string
|
||||||
mut inc_paths := []string
|
mut inc_paths := []string
|
||||||
mut lib_paths := []string
|
mut lib_paths := []string
|
||||||
mut other_flags := []string
|
mut other_flags := []string
|
||||||
for flag in cflags {
|
for flag in cflags {
|
||||||
//println('fl: $flag.name | flag arg: $flag.value')
|
// println('fl: $flag.name | flag arg: $flag.value')
|
||||||
// We need to see if the flag contains -l
|
// We need to see if the flag contains -l
|
||||||
// -l isnt recognised and these libs will be passed straight to the linker
|
// -l isnt recognised and these libs will be passed straight to the linker
|
||||||
// by the compiler
|
// by the compiler
|
||||||
|
@ -476,11 +387,11 @@ fn (cflags []CFlag) msvc_string_flags() MsvcStringFlags {
|
||||||
other_flags << flag.value
|
other_flags << flag.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mut lpaths := []string
|
mut lpaths := []string
|
||||||
for l in lib_paths {
|
for l in lib_paths {
|
||||||
lpaths << '/LIBPATH:"' + os.realpath(l) + '"'
|
lpaths << '/LIBPATH:"' + os.realpath(l) + '"'
|
||||||
}
|
}
|
||||||
|
return MsvcStringFlags{
|
||||||
return MsvcStringFlags{ real_libs, inc_paths, lpaths, other_flags }
|
real_libs,inc_paths,lpaths,other_flags}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
|
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
|
||||||
// avoid allocation
|
// avoid allocation
|
||||||
// `typ` is the type of `a`
|
// `typ` is the type of `a`
|
||||||
|
@ -13,12 +12,13 @@ fn (p mut Parser) in_optimization(typ string, ph int) {
|
||||||
// Get `a` expr value (can be a string literal, not a variable)
|
// Get `a` expr value (can be a string literal, not a variable)
|
||||||
expr := p.cgen.cur_line[ph..]
|
expr := p.cgen.cur_line[ph..]
|
||||||
is_str := typ == 'string'
|
is_str := typ == 'string'
|
||||||
//println('!! $p.expr_var.name => $name ($typ)')
|
// println('!! $p.expr_var.name => $name ($typ)')
|
||||||
for p.tok != .rsbr && p.tok != .eof {
|
for p.tok != .rsbr && p.tok != .eof {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
if is_str {
|
if is_str {
|
||||||
p.gen(' || string_eq($expr, ')
|
p.gen(' || string_eq($expr, ')
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
p.gen(' || $expr == ')
|
p.gen(' || $expr == ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ fn (p mut Parser) in_optimization(typ string, ph int) {
|
||||||
if is_str {
|
if is_str {
|
||||||
p.cgen.set_placeholder(ph, ' (string_eq(')
|
p.cgen.set_placeholder(ph, ' (string_eq(')
|
||||||
p.gen(', ')
|
p.gen(', ')
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
p.cgen.set_placeholder(ph, ' (')
|
p.cgen.set_placeholder(ph, ' (')
|
||||||
p.gen(' ==')
|
p.gen(' ==')
|
||||||
}
|
}
|
||||||
|
@ -44,3 +45,4 @@ fn (p mut Parser) in_optimization(typ string, ph int) {
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
p.check(.rsbr)
|
p.check(.rsbr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
os
|
os
|
||||||
strings
|
strings
|
||||||
|
@ -474,7 +472,7 @@ fn (p mut Parser) parse(pass Pass) {
|
||||||
.key_const {
|
.key_const {
|
||||||
p.const_decl()
|
p.const_decl()
|
||||||
}
|
}
|
||||||
.key_struct,.key_union,.key_interface {
|
.key_struct, .key_union, .key_interface {
|
||||||
p.struct_decl()
|
p.struct_decl()
|
||||||
}
|
}
|
||||||
.key_enum {
|
.key_enum {
|
||||||
|
@ -498,7 +496,7 @@ fn (p mut Parser) parse(pass Pass) {
|
||||||
// or a struct definition
|
// or a struct definition
|
||||||
p.attribute()
|
p.attribute()
|
||||||
}
|
}
|
||||||
.key_struct,.key_interface,.key_union,.lsbr {
|
.key_struct, .key_interface, .key_union, .lsbr {
|
||||||
p.struct_decl()
|
p.struct_decl()
|
||||||
}
|
}
|
||||||
.key_const {
|
.key_const {
|
||||||
|
@ -982,7 +980,7 @@ fn (p mut Parser) get_type() string {
|
||||||
// Register anon fn type
|
// Register anon fn type
|
||||||
fn_typ := Type{
|
fn_typ := Type{
|
||||||
name: f.typ_str() // 'fn (int, int) string'
|
name: f.typ_str() // 'fn (int, int) string'
|
||||||
|
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
func: f
|
func: f
|
||||||
}
|
}
|
||||||
|
@ -1364,7 +1362,7 @@ fn (p mut Parser) statement(add_semi bool) string {
|
||||||
.key_match {
|
.key_match {
|
||||||
p.match_statement(false)
|
p.match_statement(false)
|
||||||
}
|
}
|
||||||
.key_mut,.key_static {
|
.key_mut, .key_static {
|
||||||
p.var_decl()
|
p.var_decl()
|
||||||
}
|
}
|
||||||
.key_return {
|
.key_return {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
import strings
|
import strings
|
||||||
|
@ -10,37 +9,41 @@ fn sql_params2params_gen(sql_params []string, sql_types []string, qprefix string
|
||||||
mut params_gen := ''
|
mut params_gen := ''
|
||||||
for i, mparam in sql_params {
|
for i, mparam in sql_params {
|
||||||
param := mparam.trim_space()
|
param := mparam.trim_space()
|
||||||
paramtype := sql_types[ i ]
|
paramtype := sql_types[i]
|
||||||
if param[0].is_digit() {
|
if param[0].is_digit() {
|
||||||
params_gen += '${qprefix}params[$i] = int_str($param).str;\n'
|
params_gen += '${qprefix}params[$i] = int_str($param).str;\n'
|
||||||
}else if param[0] == `\'` {
|
}
|
||||||
sparam := param.trim('\'')
|
else if param[0] == `\'` {
|
||||||
|
sparam := param.trim("\'")
|
||||||
params_gen += '${qprefix}params[$i] = "$sparam";\n'
|
params_gen += '${qprefix}params[$i] = "$sparam";\n'
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// A variable like q.nr_orders
|
// A variable like q.nr_orders
|
||||||
if paramtype == 'int' {
|
if paramtype == 'int' {
|
||||||
params_gen += '${qprefix}params[$i] = int_str( $param ).str;\n'
|
params_gen += '${qprefix}params[$i] = int_str( $param ).str;\n'
|
||||||
}else if paramtype == 'string' {
|
}
|
||||||
|
else if paramtype == 'string' {
|
||||||
params_gen += '${qprefix}params[$i] = ${param}.str;\n'
|
params_gen += '${qprefix}params[$i] = ${param}.str;\n'
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
verror('orm: only int and string variable types are supported in queries')
|
verror('orm: only int and string variable types are supported in queries')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//println('>>>>>>>> params_gen')
|
// println('>>>>>>>> params_gen')
|
||||||
//println( params_gen )
|
// println( params_gen )
|
||||||
return params_gen
|
return params_gen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// `db.select from User where id == 1 && nr_bookings > 0`
|
// `db.select from User where id == 1 && nr_bookings > 0`
|
||||||
fn (p mut Parser) select_query(fn_ph int) string {
|
fn (p mut Parser) select_query(fn_ph int) string {
|
||||||
// NB: qprefix and { p.sql_i, p.sql_params, p.sql_types } SHOULD be reset for each query,
|
// NB: qprefix and { p.sql_i, p.sql_params, p.sql_types } SHOULD be reset for each query,
|
||||||
// because we can have many queries in the _same_ scope.
|
// because we can have many queries in the _same_ scope.
|
||||||
qprefix := p.get_tmp().replace('tmp','sql') + '_'
|
qprefix := p.get_tmp().replace('tmp', 'sql') + '_'
|
||||||
p.sql_i = 0
|
p.sql_i = 0
|
||||||
p.sql_params = []
|
p.sql_params = []
|
||||||
if false {}
|
if false {
|
||||||
|
}
|
||||||
p.sql_types = []
|
p.sql_types = []
|
||||||
mut q := 'select '
|
mut q := 'select '
|
||||||
p.check(.key_select)
|
p.check(.key_select)
|
||||||
|
@ -56,7 +59,7 @@ fn (p mut Parser) select_query(fn_ph int) string {
|
||||||
if typ.name == '' {
|
if typ.name == '' {
|
||||||
p.error('unknown type `$table_name`')
|
p.error('unknown type `$table_name`')
|
||||||
}
|
}
|
||||||
//fields := typ.fields.filter(typ == 'string' || typ == 'int')
|
// fields := typ.fields.filter(typ == 'string' || typ == 'int')
|
||||||
// get only string and int fields
|
// get only string and int fields
|
||||||
mut fields := []Var
|
mut fields := []Var
|
||||||
for i, field in typ.fields {
|
for i, field in typ.fields {
|
||||||
|
@ -86,20 +89,24 @@ fn (p mut Parser) select_query(fn_ph int) string {
|
||||||
q += ' from '
|
q += ' from '
|
||||||
}
|
}
|
||||||
for field in fields {
|
for field in fields {
|
||||||
//println('registering sql field var $field.name')
|
// println('registering sql field var $field.name')
|
||||||
if !(field.typ in ['string', 'int', 'bool']) {
|
if !(field.typ in ['string', 'int', 'bool']) {
|
||||||
println('orm: skipping $field.name')
|
println('orm: skipping $field.name')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
p.register_var({
|
||||||
p.register_var({ field | is_mut: true, is_used:true, is_changed:true })
|
field |
|
||||||
|
is_mut:true,
|
||||||
|
is_used:true,
|
||||||
|
is_changed:true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
q += table_name + 's'
|
q += table_name + 's'
|
||||||
// `where` statement
|
// `where` statement
|
||||||
if p.tok == .name && p.lit == 'where' {
|
if p.tok == .name && p.lit == 'where' {
|
||||||
p.next()
|
p.next()
|
||||||
p.is_sql = true
|
p.is_sql = true
|
||||||
_, expr := p.tmp_expr()
|
_,expr := p.tmp_expr()
|
||||||
p.is_sql = false
|
p.is_sql = false
|
||||||
q += ' where ' + expr
|
q += ' where ' + expr
|
||||||
}
|
}
|
||||||
|
@ -108,7 +115,7 @@ fn (p mut Parser) select_query(fn_ph int) string {
|
||||||
if p.tok == .name && p.lit == 'limit' {
|
if p.tok == .name && p.lit == 'limit' {
|
||||||
p.next()
|
p.next()
|
||||||
p.is_sql = true
|
p.is_sql = true
|
||||||
_, limit := p.tmp_expr()
|
_,limit := p.tmp_expr()
|
||||||
p.is_sql = false
|
p.is_sql = false
|
||||||
q += ' limit ' + limit
|
q += ' limit ' + limit
|
||||||
// `limit 1` means we are getting `?User`, not `[]User`
|
// `limit 1` means we are getting `?User`, not `[]User`
|
||||||
|
@ -118,11 +125,11 @@ fn (p mut Parser) select_query(fn_ph int) string {
|
||||||
}
|
}
|
||||||
println('sql query="$q"')
|
println('sql query="$q"')
|
||||||
p.cgen.insert_before('// DEBUG_SQL prefix: $qprefix | fn_ph: $fn_ph | query: "$q" ')
|
p.cgen.insert_before('// DEBUG_SQL prefix: $qprefix | fn_ph: $fn_ph | query: "$q" ')
|
||||||
|
|
||||||
if n == 'count' {
|
if n == 'count' {
|
||||||
p.cgen.set_placeholder(fn_ph, 'pg__DB_q_int(')
|
p.cgen.set_placeholder(fn_ph, 'pg__DB_q_int(')
|
||||||
p.gen(', tos2("$q"))')
|
p.gen(', tos2("$q"))')
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Build an object, assign each field.
|
// Build an object, assign each field.
|
||||||
tmp := p.get_tmp()
|
tmp := p.get_tmp()
|
||||||
mut obj_gen := strings.new_builder(300)
|
mut obj_gen := strings.new_builder(300)
|
||||||
|
@ -134,12 +141,11 @@ fn (p mut Parser) select_query(fn_ph int) string {
|
||||||
else if field.typ == 'bool' {
|
else if field.typ == 'bool' {
|
||||||
cast = 'string_bool'
|
cast = 'string_bool'
|
||||||
}
|
}
|
||||||
obj_gen.writeln('${qprefix}${tmp}.$field.name = ' +
|
obj_gen.writeln('${qprefix}${tmp}.$field.name = ' + '${cast}(*(string*)array_get(${qprefix}row.vals, $i));')
|
||||||
'${cast}(*(string*)array_get(${qprefix}row.vals, $i));')
|
|
||||||
}
|
}
|
||||||
// One object
|
// One object
|
||||||
if query_one {
|
if query_one {
|
||||||
mut params_gen := sql_params2params_gen( p.sql_params, p.sql_types, qprefix )
|
mut params_gen := sql_params2params_gen(p.sql_params, p.sql_types, qprefix)
|
||||||
p.cgen.insert_before('
|
p.cgen.insert_before('
|
||||||
|
|
||||||
char* ${qprefix}params[$p.sql_i];
|
char* ${qprefix}params[$p.sql_i];
|
||||||
|
@ -164,7 +170,7 @@ ${obj_gen.str()}
|
||||||
// Array
|
// Array
|
||||||
else {
|
else {
|
||||||
q += ' order by id'
|
q += ' order by id'
|
||||||
params_gen := sql_params2params_gen( p.sql_params, p.sql_types, qprefix )
|
params_gen := sql_params2params_gen(p.sql_params, p.sql_types, qprefix)
|
||||||
p.cgen.insert_before('char* ${qprefix}params[$p.sql_i];
|
p.cgen.insert_before('char* ${qprefix}params[$p.sql_i];
|
||||||
$params_gen
|
$params_gen
|
||||||
|
|
||||||
|
@ -181,17 +187,18 @@ for (int i = 0; i < ${qprefix}rows.len; i++) {
|
||||||
}
|
}
|
||||||
')
|
')
|
||||||
p.cgen.resetln('${qprefix}arr_$tmp')
|
p.cgen.resetln('${qprefix}arr_$tmp')
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if n == 'count' {
|
if n == 'count' {
|
||||||
return 'int'
|
return 'int'
|
||||||
} else if query_one {
|
}
|
||||||
|
else if query_one {
|
||||||
opt_type := 'Option_$table_name'
|
opt_type := 'Option_$table_name'
|
||||||
p.cgen.typedefs << 'typedef Option $opt_type;'
|
p.cgen.typedefs << 'typedef Option $opt_type;'
|
||||||
p.table.register_builtin( opt_type )
|
p.table.register_builtin(opt_type)
|
||||||
return opt_type
|
return opt_type
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
p.register_array('array_$table_name')
|
p.register_array('array_$table_name')
|
||||||
return 'array_$table_name'
|
return 'array_$table_name'
|
||||||
}
|
}
|
||||||
|
@ -203,7 +210,9 @@ fn (p mut Parser) insert_query(fn_ph int) {
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
var_name := p.check_name()
|
var_name := p.check_name()
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
var := p.find_var(var_name) or { return }
|
var := p.find_var(var_name) or {
|
||||||
|
return
|
||||||
|
}
|
||||||
typ := p.table.find_type(var.typ)
|
typ := p.table.find_type(var.typ)
|
||||||
mut fields := []Var
|
mut fields := []Var
|
||||||
for i, field in typ.fields {
|
for i, field in typ.fields {
|
||||||
|
@ -219,9 +228,9 @@ fn (p mut Parser) insert_query(fn_ph int) {
|
||||||
p.error('V orm: `id int` must be the first field in `$var.typ`')
|
p.error('V orm: `id int` must be the first field in `$var.typ`')
|
||||||
}
|
}
|
||||||
table_name := var.typ
|
table_name := var.typ
|
||||||
mut sfields := '' // 'name, city, country'
|
mut sfields := '' // 'name, city, country'
|
||||||
mut params := '' // params[0] = 'bob'; params[1] = 'Vienna';
|
mut params := '' // params[0] = 'bob'; params[1] = 'Vienna';
|
||||||
mut vals := '' // $1, $2, $3...
|
mut vals := '' // $1, $2, $3...
|
||||||
mut nr_vals := 0
|
mut nr_vals := 0
|
||||||
for i, field in fields {
|
for i, field in fields {
|
||||||
if field.name == 'id' {
|
if field.name == 'id' {
|
||||||
|
@ -233,9 +242,11 @@ fn (p mut Parser) insert_query(fn_ph int) {
|
||||||
params += 'params[${i-1}] = '
|
params += 'params[${i-1}] = '
|
||||||
if field.typ == 'string' {
|
if field.typ == 'string' {
|
||||||
params += '$var_name . $field.name .str;\n'
|
params += '$var_name . $field.name .str;\n'
|
||||||
} else if field.typ == 'int' {
|
}
|
||||||
|
else if field.typ == 'int' {
|
||||||
params += 'int_str($var_name . $field.name).str;\n'
|
params += 'int_str($var_name . $field.name).str;\n'
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
p.error('V ORM: unsupported type `$field.typ`')
|
p.error('V ORM: unsupported type `$field.typ`')
|
||||||
}
|
}
|
||||||
if i < fields.len - 1 {
|
if i < fields.len - 1 {
|
||||||
|
@ -275,11 +286,16 @@ fn (p mut Parser) update_query(fn_ph int) {
|
||||||
println('orm: skipping $f.name')
|
println('orm: skipping $f.name')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.register_var({ f | is_mut: true, is_used:true, is_changed:true })
|
p.register_var({
|
||||||
|
f |
|
||||||
|
is_mut:true,
|
||||||
|
is_used:true,
|
||||||
|
is_changed:true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
mut q := 'update ${typ.name}s set $field='
|
mut q := 'update ${typ.name}s set $field='
|
||||||
p.is_sql = true
|
p.is_sql = true
|
||||||
set_typ, expr := p.tmp_expr()
|
set_typ,expr := p.tmp_expr()
|
||||||
p.is_sql = false
|
p.is_sql = false
|
||||||
// TODO this hack should not be necessary
|
// TODO this hack should not be necessary
|
||||||
if set_typ == 'bool' {
|
if set_typ == 'bool' {
|
||||||
|
@ -289,21 +305,20 @@ fn (p mut Parser) update_query(fn_ph int) {
|
||||||
else {
|
else {
|
||||||
q += 'false'
|
q += 'false'
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
q += expr
|
q += expr
|
||||||
}
|
}
|
||||||
// where
|
// where
|
||||||
if p.tok == .name && p.lit == 'where' {
|
if p.tok == .name && p.lit == 'where' {
|
||||||
p.next()
|
p.next()
|
||||||
p.is_sql = true
|
p.is_sql = true
|
||||||
_, wexpr := p.tmp_expr()
|
_,wexpr := p.tmp_expr()
|
||||||
p.is_sql = false
|
p.is_sql = false
|
||||||
q += ' where ' + wexpr
|
q += ' where ' + wexpr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
nr_vals := 0
|
nr_vals := 0
|
||||||
p.cgen.insert_before('char* params[$nr_vals];')// + params)
|
p.cgen.insert_before('char* params[$nr_vals];') // + params)
|
||||||
p.cgen.set_placeholder(fn_ph, 'PQexecParams( ')
|
p.cgen.set_placeholder(fn_ph, 'PQexecParams( ')
|
||||||
println('update q="$q"')
|
println('update q="$q"')
|
||||||
p.genln('.conn, "$q", $nr_vals, 0, params, 0, 0, 0)')
|
p.genln('.conn, "$q", $nr_vals, 0, params, 0, 0, 0)')
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct ScanRes {
|
||||||
lit string
|
lit string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_res(tok TokenKind,lit string) ScanRes {
|
fn scan_res(tok TokenKind, lit string) ScanRes {
|
||||||
return ScanRes{
|
return ScanRes{
|
||||||
tok,lit}
|
tok,lit}
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
name := s.ident_name()
|
name := s.ident_name()
|
||||||
// tmp hack to detect . in ${}
|
// tmp hack to detect . in ${}
|
||||||
// Check if not .eof to prevent panic
|
// Check if not .eof to prevent panic
|
||||||
next_char := if s.pos + 1 < s.text.len {s.text[s.pos + 1]}else {`\0`}
|
next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` }
|
||||||
if is_key(name) {
|
if is_key(name) {
|
||||||
return scan_res(key_to_token(name), '')
|
return scan_res(key_to_token(name), '')
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
if c == `)` && s.inter_start {
|
if c == `)` && s.inter_start {
|
||||||
s.inter_end = true
|
s.inter_end = true
|
||||||
s.inter_start = false
|
s.inter_start = false
|
||||||
next_char := if s.pos + 1 < s.text.len {s.text[s.pos + 1]}else {`\0`}
|
next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` }
|
||||||
if next_char == s.quote {
|
if next_char == s.quote {
|
||||||
s.inside_string = false
|
s.inside_string = false
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
`?` {
|
`?` {
|
||||||
return scan_res(.question, '')
|
return scan_res(.question, '')
|
||||||
}
|
}
|
||||||
single_quote,double_quote {
|
single_quote, double_quote {
|
||||||
return scan_res(.str, s.ident_string())
|
return scan_res(.str, s.ident_string())
|
||||||
}
|
}
|
||||||
`\`` {
|
`\`` {
|
||||||
|
@ -659,7 +659,7 @@ fn (s &Scanner) current_column() int {
|
||||||
return s.pos - s.last_nl_pos
|
return s.pos - s.last_nl_pos
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s Scanner) count_symbol_before(p int,sym byte) int {
|
fn (s Scanner) count_symbol_before(p int, sym byte) int {
|
||||||
mut count := 0
|
mut count := 0
|
||||||
for i := p; i >= 0; i-- {
|
for i := p; i >= 0; i-- {
|
||||||
if s.text[i] != sym {
|
if s.text[i] != sym {
|
||||||
|
@ -775,10 +775,10 @@ fn (s mut Scanner) ident_char() string {
|
||||||
return '`'
|
return '`'
|
||||||
}
|
}
|
||||||
// Escapes a `'` character
|
// Escapes a `'` character
|
||||||
return if c == "\'" {'\\' + c}else {c}
|
return if c == "\'" { '\\' + c } else { c }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s &Scanner) expect(want string,start_pos int) bool {
|
fn (s &Scanner) expect(want string, start_pos int) bool {
|
||||||
end_pos := start_pos + want.len
|
end_pos := start_pos + want.len
|
||||||
if start_pos < 0 || start_pos >= s.text.len {
|
if start_pos < 0 || start_pos >= s.text.len {
|
||||||
return false
|
return false
|
||||||
|
@ -841,7 +841,7 @@ fn (s mut Scanner) inc_line_number() {
|
||||||
fn (s Scanner) line(n int) string {
|
fn (s Scanner) line(n int) string {
|
||||||
mut res := ''
|
mut res := ''
|
||||||
if n >= 0 && n < s.line_ends.len {
|
if n >= 0 && n < s.line_ends.len {
|
||||||
nline_start := if n == 0 {0}else {s.line_ends[n - 1]}
|
nline_start := if n == 0 { 0 } else { s.line_ends[n - 1] }
|
||||||
nline_end := s.line_ends[n]
|
nline_end := s.line_ends[n]
|
||||||
if nline_start <= nline_end {
|
if nline_start <= nline_end {
|
||||||
res = s.text[nline_start..nline_end]
|
res = s.text[nline_start..nline_end]
|
||||||
|
@ -889,3 +889,4 @@ fn (s &Scanner) validate_var_name(name string) {
|
||||||
s.error('bad variable name `$name`\n' + 'looks like you have a multi-word name without separating them with `_`' + '\nfor example, use `registration_date` instead of `registrationdate` ')
|
s.error('bad variable name `$name`\n' + 'looks like you have a multi-word name without separating them with `_`' + '\nfor example, use `registration_date` instead of `registrationdate` ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ fn (p mut Parser) string_expr() {
|
||||||
str := p.lit
|
str := p.lit
|
||||||
// No ${}, just return a simple string
|
// No ${}, just return a simple string
|
||||||
if p.peek() != .str_dollar || is_raw {
|
if p.peek() != .str_dollar || is_raw {
|
||||||
f := if is_raw {cescaped_path(str)}else {format_str(str)}
|
f := if is_raw { cescaped_path(str) } else { format_str(str) }
|
||||||
// `C.puts('hi')` => `puts("hi");`
|
// `C.puts('hi')` => `puts("hi");`
|
||||||
/*
|
/*
|
||||||
Calling a C function sometimes requires a call to a string method
|
Calling a C function sometimes requires a call to a string method
|
||||||
|
@ -152,3 +152,4 @@ fn (p mut Parser) string_expr() {
|
||||||
p.gen('_STR($format$args)')
|
p.gen('_STR($format$args)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
strings
|
strings
|
||||||
)
|
)
|
||||||
|
|
||||||
// also unions and interfaces
|
// also unions and interfaces
|
||||||
|
|
||||||
|
|
||||||
fn (p mut Parser) struct_decl() {
|
fn (p mut Parser) struct_decl() {
|
||||||
is_pub := p.tok == .key_pub
|
is_pub := p.tok == .key_pub
|
||||||
if is_pub {
|
if is_pub {
|
||||||
|
@ -67,18 +67,18 @@ fn (p mut Parser) struct_decl() {
|
||||||
}
|
}
|
||||||
mut typ := p.table.find_type(name)
|
mut typ := p.table.find_type(name)
|
||||||
if p.pass == .decl && p.table.known_type_fast(typ) {
|
if p.pass == .decl && p.table.known_type_fast(typ) {
|
||||||
//if name in reserved_type_param_names {
|
// if name in reserved_type_param_names {
|
||||||
//p.error('name `$name` is reserved for type parameters')
|
// p.error('name `$name` is reserved for type parameters')
|
||||||
//} else {
|
// } else {
|
||||||
p.error('type `$name` redeclared')
|
p.error('type `$name` redeclared')
|
||||||
//}
|
// }
|
||||||
}
|
}
|
||||||
if is_objc {
|
if is_objc {
|
||||||
// Forward declaration of an Objective-C interface with `@class` :)
|
// Forward declaration of an Objective-C interface with `@class` :)
|
||||||
p.gen_typedef('@class $name;')
|
p.gen_typedef('@class $name;')
|
||||||
}
|
}
|
||||||
else if !is_c {
|
else if !is_c {
|
||||||
kind := if is_union {'union'} else {'struct'}
|
kind := if is_union { 'union' } else { 'struct' }
|
||||||
p.gen_typedef('typedef $kind $name $name;')
|
p.gen_typedef('typedef $kind $name $name;')
|
||||||
}
|
}
|
||||||
// Register the type
|
// Register the type
|
||||||
|
@ -96,7 +96,7 @@ fn (p mut Parser) struct_decl() {
|
||||||
p.table.rewrite_type(typ)
|
p.table.rewrite_type(typ)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typ = Type {
|
typ = Type{
|
||||||
name: name
|
name: name
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
is_c: is_c
|
is_c: is_c
|
||||||
|
@ -114,14 +114,14 @@ fn (p mut Parser) struct_decl() {
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
// Struct fields
|
// Struct fields
|
||||||
mut access_mod := AccessMod.private
|
mut access_mod := AccessMod.private
|
||||||
//mut is_pub_field := false
|
// mut is_pub_field := false
|
||||||
//mut is_mut := false
|
// mut is_mut := false
|
||||||
mut names := []string// to avoid dup names TODO alloc perf
|
mut names := []string // to avoid dup names TODO alloc perf
|
||||||
mut fmt_max_len := p.table.max_field_len[name]
|
mut fmt_max_len := p.table.max_field_len[name]
|
||||||
//println('fmt max len = $max_len nrfields=$typ.fields.len pass=$p.pass')
|
// println('fmt max len = $max_len nrfields=$typ.fields.len pass=$p.pass')
|
||||||
if !is_ph && p.first_pass() {
|
if !is_ph && p.first_pass() {
|
||||||
p.table.register_type(typ)
|
p.table.register_type(typ)
|
||||||
//println('registering 1 nrfields=$typ.fields.len')
|
// println('registering 1 nrfields=$typ.fields.len')
|
||||||
}
|
}
|
||||||
mut did_gen_something := false
|
mut did_gen_something := false
|
||||||
mut used := []AccessMod
|
mut used := []AccessMod
|
||||||
|
@ -136,7 +136,8 @@ fn (p mut Parser) struct_decl() {
|
||||||
p.fspace()
|
p.fspace()
|
||||||
new_access_mod = .public_mut
|
new_access_mod = .public_mut
|
||||||
p.next() // skip `mut`
|
p.next() // skip `mut`
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
new_access_mod = .public
|
new_access_mod = .public
|
||||||
}
|
}
|
||||||
if new_access_mod in used {
|
if new_access_mod in used {
|
||||||
|
@ -203,7 +204,7 @@ fn (p mut Parser) struct_decl() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// `pub` access mod
|
// `pub` access mod
|
||||||
//access_mod := if is_pub_field { AccessMod.public } else { AccessMod.private}
|
// access_mod := if is_pub_field { AccessMod.public } else { AccessMod.private}
|
||||||
p.fspace()
|
p.fspace()
|
||||||
tt := p.get_type2()
|
tt := p.get_type2()
|
||||||
field_type := tt.name
|
field_type := tt.name
|
||||||
|
@ -222,11 +223,11 @@ fn (p mut Parser) struct_decl() {
|
||||||
// `a int = 4`
|
// `a int = 4`
|
||||||
if p.tok == .assign {
|
if p.tok == .assign {
|
||||||
p.next()
|
p.next()
|
||||||
def_val_type, expr := p.tmp_expr()
|
def_val_type,expr := p.tmp_expr()
|
||||||
if def_val_type != field_type {
|
if def_val_type != field_type {
|
||||||
p.error('expected `$field_type` but got `$def_val_type`')
|
p.error('expected `$field_type` but got `$def_val_type`')
|
||||||
}
|
}
|
||||||
//println('pass=$p.pass $typ.name ADDING field=$field_name "$def_val_type" "$expr"')
|
// println('pass=$p.pass $typ.name ADDING field=$field_name "$def_val_type" "$expr"')
|
||||||
if !p.first_pass() {
|
if !p.first_pass() {
|
||||||
p.table.add_default_val(i, typ.name, expr)
|
p.table.add_default_val(i, typ.name, expr)
|
||||||
}
|
}
|
||||||
|
@ -241,12 +242,15 @@ fn (p mut Parser) struct_decl() {
|
||||||
p.check(.colon)
|
p.check(.colon)
|
||||||
mut val := ''
|
mut val := ''
|
||||||
match p.tok {
|
match p.tok {
|
||||||
.name { val = p.check_name() }
|
.name {
|
||||||
.str { val = p.check_string() }
|
val = p.check_name()
|
||||||
|
}
|
||||||
|
.str {
|
||||||
|
val = p.check_string()
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
p.error('attribute value should be either name or string')
|
p.error('attribute value should be either name or string')
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
attr += ':' + val
|
attr += ':' + val
|
||||||
}
|
}
|
||||||
p.check(.rsbr)
|
p.check(.rsbr)
|
||||||
|
@ -257,24 +261,22 @@ fn (p mut Parser) struct_decl() {
|
||||||
did_gen_something = true
|
did_gen_something = true
|
||||||
is_mut := access_mod in [.private_mut, .public_mut, .global]
|
is_mut := access_mod in [.private_mut, .public_mut, .global]
|
||||||
if p.first_pass() {
|
if p.first_pass() {
|
||||||
p.table.add_field(typ.name, field_name, field_type, is_mut,
|
p.table.add_field(typ.name, field_name, field_type, is_mut, attr, access_mod)
|
||||||
attr, access_mod)
|
|
||||||
}
|
}
|
||||||
p.fgen_nl() // newline between struct fields
|
p.fgen_nl() // newline between struct fields
|
||||||
}
|
}
|
||||||
if p.scanner.is_fmt && p.pass == .decl {
|
if p.scanner.is_fmt && p.pass == .decl {
|
||||||
p.table.max_field_len[typ.name] = fmt_max_len
|
p.table.max_field_len[typ.name] = fmt_max_len
|
||||||
}
|
}
|
||||||
//p.fgen_require_nl()
|
// p.fgen_require_nl()
|
||||||
p.check(.rcbr)
|
p.check(.rcbr)
|
||||||
if !is_c && !did_gen_something && p.first_pass() {
|
if !is_c && !did_gen_something && p.first_pass() {
|
||||||
p.table.add_field(typ.name, '', 'EMPTY_STRUCT_DECLARATION', false, '', .private)
|
p.table.add_field(typ.name, '', 'EMPTY_STRUCT_DECLARATION', false, '', .private)
|
||||||
}
|
}
|
||||||
p.fgen_nl()
|
p.fgen_nl()
|
||||||
p.fgen_nl()
|
p.fgen_nl()
|
||||||
//p.fgenln('//kek')
|
// p.fgenln('//kek')
|
||||||
}
|
}
|
||||||
|
|
||||||
// `User{ foo: bar }`
|
// `User{ foo: bar }`
|
||||||
fn (p mut Parser) struct_init(typ string) string {
|
fn (p mut Parser) struct_init(typ string) string {
|
||||||
p.is_struct_init = true
|
p.is_struct_init = true
|
||||||
|
@ -282,7 +284,9 @@ fn (p mut Parser) struct_init(typ string) string {
|
||||||
if !t.is_public && t.mod != p.mod {
|
if !t.is_public && t.mod != p.mod {
|
||||||
p.warn('type `$t.name` is private')
|
p.warn('type `$t.name` is private')
|
||||||
}
|
}
|
||||||
if p.gen_struct_init(typ, t) { return typ }
|
if p.gen_struct_init(typ, t) {
|
||||||
|
return typ
|
||||||
|
}
|
||||||
ptr := typ.contains('*')
|
ptr := typ.contains('*')
|
||||||
mut did_gen_something := false
|
mut did_gen_something := false
|
||||||
// Loop thru all struct init keys and assign values
|
// Loop thru all struct init keys and assign values
|
||||||
|
@ -292,7 +296,7 @@ fn (p mut Parser) struct_init(typ string) string {
|
||||||
peek := p.peek()
|
peek := p.peek()
|
||||||
if peek == .colon || p.tok == .rcbr {
|
if peek == .colon || p.tok == .rcbr {
|
||||||
for p.tok != .rcbr {
|
for p.tok != .rcbr {
|
||||||
field := if typ != 'Option' { p.table.var_cgen_name( p.check_name() ) } else { p.check_name() }
|
field := if typ != 'Option' { p.table.var_cgen_name(p.check_name()) } else { p.check_name() }
|
||||||
if !p.first_pass() && !t.has_field(field) {
|
if !p.first_pass() && !t.has_field(field) {
|
||||||
p.error('`$t.name` has no field `$field`')
|
p.error('`$t.name` has no field `$field`')
|
||||||
}
|
}
|
||||||
|
@ -312,7 +316,7 @@ fn (p mut Parser) struct_init(typ string) string {
|
||||||
p.check(.colon)
|
p.check(.colon)
|
||||||
p.fspace()
|
p.fspace()
|
||||||
p.expected_type = f.typ
|
p.expected_type = f.typ
|
||||||
p.check_types(p.bool_expression(), f.typ)
|
p.check_types(p.bool_expression(), f.typ)
|
||||||
if p.tok == .comma {
|
if p.tok == .comma {
|
||||||
p.next()
|
p.next()
|
||||||
p.fremove_last()
|
p.fremove_last()
|
||||||
|
@ -330,18 +334,15 @@ fn (p mut Parser) struct_init(typ string) string {
|
||||||
}
|
}
|
||||||
// Zero values: init all fields (ints to 0, strings to '' etc)
|
// Zero values: init all fields (ints to 0, strings to '' etc)
|
||||||
for i, field in t.fields {
|
for i, field in t.fields {
|
||||||
sanitized_name := if typ != 'Option' {
|
sanitized_name := if typ != 'Option' { p.table.var_cgen_name(field.name) } else { field.name }
|
||||||
p.table.var_cgen_name( field.name )
|
|
||||||
} else {
|
|
||||||
field.name
|
|
||||||
}
|
|
||||||
// println('### field.name')
|
// println('### field.name')
|
||||||
// Skip if this field has already been assigned to
|
// Skip if this field has already been assigned to
|
||||||
if sanitized_name in inited_fields {
|
if sanitized_name in inited_fields {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
field_typ := field.typ
|
field_typ := field.typ
|
||||||
if !p.builtin_mod && field_typ.ends_with('*') && p.mod != 'os' { //&&
|
if !p.builtin_mod && field_typ.ends_with('*') && p.mod != 'os' {
|
||||||
|
// &&
|
||||||
p.warn('reference field `${typ}.${field.name}` must be initialized')
|
p.warn('reference field `${typ}.${field.name}` must be initialized')
|
||||||
}
|
}
|
||||||
// init map fields
|
// init map fields
|
||||||
|
@ -357,11 +358,7 @@ fn (p mut Parser) struct_init(typ string) string {
|
||||||
}
|
}
|
||||||
// Did the user provide a default value for this struct field?
|
// Did the user provide a default value for this struct field?
|
||||||
// Use it. Otherwise zero it.
|
// Use it. Otherwise zero it.
|
||||||
def_val := if t.default_vals.len > i && t.default_vals[i] != '' {
|
def_val := if t.default_vals.len > i && t.default_vals[i] != '' { t.default_vals[i] } else { type_default(field_typ) }
|
||||||
t.default_vals[i]
|
|
||||||
} else {
|
|
||||||
type_default(field_typ)
|
|
||||||
}
|
|
||||||
if def_val != '' && def_val != '{0}' {
|
if def_val != '' && def_val != '{0}' {
|
||||||
p.gen_struct_field_init(sanitized_name)
|
p.gen_struct_field_init(sanitized_name)
|
||||||
p.gen(def_val)
|
p.gen(def_val)
|
||||||
|
@ -419,4 +416,3 @@ fn (p mut Parser) struct_init(typ string) string {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -875,13 +875,13 @@ fn (p mut Parser) typ_to_fmt(typ string, level int) string {
|
||||||
'ustring' {
|
'ustring' {
|
||||||
return '%.*s'
|
return '%.*s'
|
||||||
}
|
}
|
||||||
'byte','bool','int','char','byte','i16','i8' {
|
'byte', 'bool', 'int', 'char', 'byte', 'i16', 'i8' {
|
||||||
return '%d'
|
return '%d'
|
||||||
}
|
}
|
||||||
'u16','u32' {
|
'u16', 'u32' {
|
||||||
return '%u'
|
return '%u'
|
||||||
}
|
}
|
||||||
'f64','f32' {
|
'f64', 'f32' {
|
||||||
return '%f'
|
return '%f'
|
||||||
}
|
}
|
||||||
'i64' {
|
'i64' {
|
||||||
|
@ -890,7 +890,7 @@ fn (p mut Parser) typ_to_fmt(typ string, level int) string {
|
||||||
'u64' {
|
'u64' {
|
||||||
return '%llu'
|
return '%llu'
|
||||||
}
|
}
|
||||||
'byte*','byteptr' {
|
'byte*', 'byteptr' {
|
||||||
return '%s'
|
return '%s'
|
||||||
}
|
}
|
||||||
// case 'array_string': return '%s'
|
// case 'array_string': return '%s'
|
||||||
|
|
|
@ -1,25 +1,23 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
struct Token {
|
struct Token {
|
||||||
tok TokenKind // the token number/enum; for quick comparisons
|
tok TokenKind // the token number/enum; for quick comparisons
|
||||||
lit string // literal representation of the token
|
lit string // literal representation of the token
|
||||||
line_nr int // the line number in the source where the token occured
|
line_nr int // the line number in the source where the token occured
|
||||||
name_idx int // name table index for O(1) lookup
|
name_idx int // name table index for O(1) lookup
|
||||||
pos int // the position of the token in scanner text
|
pos int // the position of the token in scanner text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum TokenKind {
|
enum TokenKind {
|
||||||
eof
|
eof
|
||||||
name // user
|
name // user
|
||||||
number // 123
|
number // 123
|
||||||
str // 'foo'
|
str // 'foo'
|
||||||
str_inter // 'name=$user.name'
|
str_inter // 'name=$user.name'
|
||||||
chartoken // `A`
|
chartoken // `A`
|
||||||
plus
|
plus
|
||||||
minus
|
minus
|
||||||
mul
|
mul
|
||||||
|
@ -44,7 +42,7 @@ enum TokenKind {
|
||||||
str_dollar
|
str_dollar
|
||||||
left_shift
|
left_shift
|
||||||
righ_shift
|
righ_shift
|
||||||
//at // @
|
// at // @
|
||||||
assign // =
|
assign // =
|
||||||
decl_assign // :=
|
decl_assign // :=
|
||||||
plus_assign // +=
|
plus_assign // +=
|
||||||
|
@ -102,7 +100,7 @@ enum TokenKind {
|
||||||
key_import_const
|
key_import_const
|
||||||
key_in
|
key_in
|
||||||
key_interface
|
key_interface
|
||||||
//key_it
|
// key_it
|
||||||
key_match
|
key_match
|
||||||
key_module
|
key_module
|
||||||
key_mut
|
key_mut
|
||||||
|
@ -114,7 +112,7 @@ enum TokenKind {
|
||||||
key_switch
|
key_switch
|
||||||
key_true
|
key_true
|
||||||
key_type
|
key_type
|
||||||
//typeof
|
// typeof
|
||||||
key_orelse
|
key_orelse
|
||||||
key_union
|
key_union
|
||||||
key_pub
|
key_pub
|
||||||
|
@ -125,6 +123,8 @@ enum TokenKind {
|
||||||
|
|
||||||
// build_keys genereates a map with keywords' string values:
|
// build_keys genereates a map with keywords' string values:
|
||||||
// Keywords['return'] == .key_return
|
// Keywords['return'] == .key_return
|
||||||
|
|
||||||
|
|
||||||
fn build_keys() map[string]int {
|
fn build_keys() map[string]int {
|
||||||
mut res := map[string]int
|
mut res := map[string]int
|
||||||
for t := int(TokenKind.keyword_beg) + 1; t < int(TokenKind.keyword_end); t++ {
|
for t := int(TokenKind.keyword_beg) + 1; t < int(TokenKind.keyword_end); t++ {
|
||||||
|
@ -163,7 +163,7 @@ fn build_token_str() []string {
|
||||||
s[TokenKind.dotdot] = '..'
|
s[TokenKind.dotdot] = '..'
|
||||||
s[TokenKind.ellipsis] = '...'
|
s[TokenKind.ellipsis] = '...'
|
||||||
s[TokenKind.comma] = ','
|
s[TokenKind.comma] = ','
|
||||||
//s[TokenKind.at] = '@'
|
// s[TokenKind.at] = '@'
|
||||||
s[TokenKind.semicolon] = ';'
|
s[TokenKind.semicolon] = ';'
|
||||||
s[TokenKind.colon] = ':'
|
s[TokenKind.colon] = ':'
|
||||||
s[TokenKind.arrow] = '=>'
|
s[TokenKind.arrow] = '=>'
|
||||||
|
@ -202,7 +202,7 @@ fn build_token_str() []string {
|
||||||
s[TokenKind.key_assert] = 'assert'
|
s[TokenKind.key_assert] = 'assert'
|
||||||
s[TokenKind.key_struct] = 'struct'
|
s[TokenKind.key_struct] = 'struct'
|
||||||
s[TokenKind.key_if] = 'if'
|
s[TokenKind.key_if] = 'if'
|
||||||
//s[TokenKind.key_it] = 'it'
|
// s[TokenKind.key_it] = 'it'
|
||||||
s[TokenKind.key_else] = 'else'
|
s[TokenKind.key_else] = 'else'
|
||||||
s[TokenKind.key_asm] = 'asm'
|
s[TokenKind.key_asm] = 'asm'
|
||||||
s[TokenKind.key_return] = 'return'
|
s[TokenKind.key_return] = 'return'
|
||||||
|
@ -223,7 +223,7 @@ fn build_token_str() []string {
|
||||||
s[TokenKind.key_import] = 'import'
|
s[TokenKind.key_import] = 'import'
|
||||||
s[TokenKind.key_embed] = 'embed'
|
s[TokenKind.key_embed] = 'embed'
|
||||||
s[TokenKind.key_unsafe] = 'unsafe'
|
s[TokenKind.key_unsafe] = 'unsafe'
|
||||||
//Tokens[key_typeof] = 'typeof'
|
// Tokens[key_typeof] = 'typeof'
|
||||||
s[TokenKind.key_enum] = 'enum'
|
s[TokenKind.key_enum] = 'enum'
|
||||||
s[TokenKind.key_interface] = 'interface'
|
s[TokenKind.key_interface] = 'interface'
|
||||||
s[TokenKind.key_pub] = 'pub'
|
s[TokenKind.key_pub] = 'pub'
|
||||||
|
@ -262,19 +262,11 @@ pub fn (t TokenKind) str() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t TokenKind) is_decl() bool {
|
fn (t TokenKind) is_decl() bool {
|
||||||
return t in [.key_enum, .key_interface, .key_fn,
|
return t in [.key_enum, .key_interface, .key_fn, .key_struct, .key_type, .key_const, .key_import_const, .key_pub, .eof]
|
||||||
.key_struct ,.key_type, .key_const, .key_import_const, .key_pub, .eof]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AssignTokens = [
|
AssignTokens = [TokenKind.assign, .plus_assign, .minus_assign, .mult_assign, .div_assign, .xor_assign, .mod_assign, .or_assign, .and_assign, .righ_shift_assign, .left_shift_assign]
|
||||||
TokenKind.assign, .plus_assign, .minus_assign,
|
|
||||||
.mult_assign, .div_assign, .xor_assign,
|
|
||||||
.mod_assign,
|
|
||||||
.or_assign, .and_assign, .righ_shift_assign,
|
|
||||||
.left_shift_assign
|
|
||||||
]
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fn (t TokenKind) is_assign() bool {
|
fn (t TokenKind) is_assign() bool {
|
||||||
|
@ -293,7 +285,6 @@ fn (t []TokenKind) contains(val TokenKind) bool {
|
||||||
pub fn (t Token) str() string {
|
pub fn (t Token) str() string {
|
||||||
if t.tok == .number {
|
if t.tok == .number {
|
||||||
return t.lit
|
return t.lit
|
||||||
|
|
||||||
}
|
}
|
||||||
if t.tok == .chartoken {
|
if t.tok == .chartoken {
|
||||||
return '`$t.lit`'
|
return '`$t.lit`'
|
||||||
|
|
|
@ -251,7 +251,7 @@ fn (p &Parser) gen_fmt() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//files := ['get_type.v']
|
//files := ['get_type.v']
|
||||||
if !p.file_path.contains('vlib/builtin') {return}
|
if p.file_path.contains('vfmt') {return}
|
||||||
//if !(p.file_name in files) { return }
|
//if !(p.file_name in files) { return }
|
||||||
path := os.tmpdir() + '/' + p.file_name
|
path := os.tmpdir() + '/' + p.file_name
|
||||||
println('generating ${path}')
|
println('generating ${path}')
|
||||||
|
|
|
@ -84,9 +84,8 @@ V package management commands:
|
||||||
remove [module] Removes an installed module, or ALL installed modules at once, when no module name is given.
|
remove [module] Removes an installed module, or ALL installed modules at once, when no module name is given.
|
||||||
'
|
'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- To disable automatic formatting:
|
- To disable automatic formatting:
|
||||||
v -nofmt file.v
|
v -nofmt file.v
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module compiler
|
module compiler
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -9,13 +8,16 @@ import filepath
|
||||||
|
|
||||||
pub fn get_vtmp_folder() string {
|
pub fn get_vtmp_folder() string {
|
||||||
vtmp := filepath.join(os.tmpdir(),'v')
|
vtmp := filepath.join(os.tmpdir(),'v')
|
||||||
if !os.is_dir( vtmp ) {
|
if !os.is_dir(vtmp) {
|
||||||
os.mkdir(vtmp) or { panic(err) }
|
os.mkdir(vtmp)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return vtmp
|
return vtmp
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_vtmp_filename(base_file_name string, postfix string) string {
|
pub fn get_vtmp_filename(base_file_name string, postfix string) string {
|
||||||
vtmp := get_vtmp_folder()
|
vtmp := get_vtmp_folder()
|
||||||
return os.realpath( filepath.join(vtmp, os.filename( os.realpath(base_file_name) ) + postfix) )
|
return os.realpath(filepath.join(vtmp,os.filename(os.realpath(base_file_name)) + postfix))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,41 +2,43 @@ module compiler
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
pub fn launch_tool(tname string){
|
pub fn launch_tool(tname string) {
|
||||||
vexe := vexe_path()
|
vexe := vexe_path()
|
||||||
vroot := os.dir(vexe)
|
vroot := os.dir(vexe)
|
||||||
mut oargs := os.args
|
mut oargs := os.args
|
||||||
oargs[0] = '"$vexe"' // make it more explicit
|
oargs[0] = '"$vexe"' // make it more explicit
|
||||||
tool_exe := os.realpath('$vroot/tools/$tname')
|
tool_exe := os.realpath('$vroot/tools/$tname')
|
||||||
tool_source := os.realpath('$vroot/tools/${tname}.v')
|
tool_source := os.realpath('$vroot/tools/${tname}.v')
|
||||||
//////////////////////////////////////////////////////
|
// ////////////////////////////////////////////////////
|
||||||
tool_args := oargs.join(' ')
|
tool_args := oargs.join(' ')
|
||||||
tool_command := '"$tool_exe" $tool_args'
|
tool_command := '"$tool_exe" $tool_args'
|
||||||
//println('Launching: "$tool_command" ...')
|
// println('Launching: "$tool_command" ...')
|
||||||
|
|
||||||
mut tool_should_be_recompiled := false
|
mut tool_should_be_recompiled := false
|
||||||
if !os.exists( tool_exe ) {
|
if !os.exists(tool_exe) {
|
||||||
// fresh checkout
|
// fresh checkout
|
||||||
tool_should_be_recompiled = true
|
tool_should_be_recompiled = true
|
||||||
}else{
|
}
|
||||||
if os.file_last_mod_unix( tool_exe ) <= os.file_last_mod_unix( vexe ) {
|
else {
|
||||||
|
if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(vexe) {
|
||||||
// v was recompiled, maybe after v up ...
|
// v was recompiled, maybe after v up ...
|
||||||
// rebuild the tool too just in case
|
// rebuild the tool too just in case
|
||||||
tool_should_be_recompiled = true
|
tool_should_be_recompiled = true
|
||||||
}
|
}
|
||||||
if os.file_last_mod_unix( tool_exe ) <= os.file_last_mod_unix( tool_source ) {
|
if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(tool_source) {
|
||||||
// the user changed the source code of the tool
|
// the user changed the source code of the tool
|
||||||
tool_should_be_recompiled = true
|
tool_should_be_recompiled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tool_should_be_recompiled {
|
if tool_should_be_recompiled {
|
||||||
compilation_command := '"$vexe" "$tool_source"'
|
compilation_command := '"$vexe" "$tool_source"'
|
||||||
//println('Compiling $tname with: "$compilation_command"')
|
// println('Compiling $tname with: "$compilation_command"')
|
||||||
tool_compilation := os.exec(compilation_command) or { panic(err) }
|
tool_compilation := os.exec(compilation_command)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
if tool_compilation.exit_code != 0 {
|
if tool_compilation.exit_code != 0 {
|
||||||
panic('V tool "$tool_source" could not be compiled\n' + tool_compilation.output)
|
panic('V tool "$tool_source" could not be compiled\n' + tool_compilation.output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit( os.system(tool_command) )
|
exit(os.system(tool_command))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module x64
|
module x64
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
@ -14,19 +13,14 @@ const (
|
||||||
ei_class = 4
|
ei_class = 4
|
||||||
elfclass64 = 2
|
elfclass64 = 2
|
||||||
elfdata2lsb = 1
|
elfdata2lsb = 1
|
||||||
|
|
||||||
ev_current = 1
|
ev_current = 1
|
||||||
elf_osabi = 0
|
elf_osabi = 0
|
||||||
|
|
||||||
// ELF file types
|
// ELF file types
|
||||||
et_rel = 1
|
et_rel = 1
|
||||||
et_exec = 2
|
et_exec = 2
|
||||||
et_dyn = 3
|
et_dyn = 3
|
||||||
|
|
||||||
e_machine = 0x3e
|
e_machine = 0x3e
|
||||||
|
|
||||||
shn_xindex = 0xffff
|
shn_xindex = 0xffff
|
||||||
|
|
||||||
sht_null = 0
|
sht_null = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,14 +28,13 @@ const (
|
||||||
segment_start = 0x400000
|
segment_start = 0x400000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
pub fn (g mut Gen) generate_elf_header() {
|
pub fn (g mut Gen) generate_elf_header() {
|
||||||
g.buf << [byte(mag0), mag1, mag2, mag3]
|
g.buf << [byte(mag0), mag1, mag2, mag3]
|
||||||
g.buf << elfclass64 // file class
|
g.buf << elfclass64 // file class
|
||||||
g.buf << elfdata2lsb // data encoding
|
g.buf << elfdata2lsb // data encoding
|
||||||
g.buf << ev_current // file version
|
g.buf << ev_current // file version
|
||||||
g.buf << 1//elf_osabi
|
g.buf << 1 // elf_osabi
|
||||||
g.write64(0)//et_rel) // et_rel for .o
|
g.write64(0) // et_rel) // et_rel for .o
|
||||||
g.write16(2) // e_type
|
g.write16(2) // e_type
|
||||||
g.write16(e_machine) //
|
g.write16(e_machine) //
|
||||||
g.write32(ev_current) // e_version
|
g.write32(ev_current) // e_version
|
||||||
|
@ -70,7 +63,7 @@ pub fn (g mut Gen) generate_elf_header() {
|
||||||
// user code starts here at
|
// user code starts here at
|
||||||
// address: 00070 and a half
|
// address: 00070 and a half
|
||||||
g.code_start_pos = g.buf.len
|
g.code_start_pos = g.buf.len
|
||||||
g.call(0)// call main function, it's not guaranteed to be the first
|
g.call(0) // call main function, it's not guaranteed to be the first
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (g mut Gen) generate_elf_footer() {
|
pub fn (g mut Gen) generate_elf_footer() {
|
||||||
|
@ -84,19 +77,21 @@ pub fn (g mut Gen) generate_elf_footer() {
|
||||||
g.write64_at(segment_start + g.buf.len, int(g.str_pos[i]))
|
g.write64_at(segment_start + g.buf.len, int(g.str_pos[i]))
|
||||||
g.write_string(s)
|
g.write_string(s)
|
||||||
g.write8(6)
|
g.write8(6)
|
||||||
}
|
}
|
||||||
// Now we know the file size, set it
|
// Now we know the file size, set it
|
||||||
file_size := g.buf.len
|
file_size := g.buf.len
|
||||||
g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value
|
g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value
|
||||||
g.write64_at(file_size, g.file_size_pos+8)
|
g.write64_at(file_size, g.file_size_pos + 8)
|
||||||
// call main function, it's not guaranteed to be the first
|
// call main function, it's not guaranteed to be the first
|
||||||
// we generated call(0) ("e8 0")
|
// we generated call(0) ("e8 0")
|
||||||
// no need to replace "0" with a relative address of the main function
|
// no need to replace "0" with a relative address of the main function
|
||||||
// +1 is for "e8"
|
// +1 is for "e8"
|
||||||
// -5 is for "e8 00 00 00 00"
|
// -5 is for "e8 00 00 00 00"
|
||||||
g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos+1)
|
g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos + 1)
|
||||||
// Create the binary
|
// Create the binary
|
||||||
mut f := os.create(g.out_name) or { panic(err) }
|
mut f := os.create(g.out_name)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
os.chmod(g.out_name, 0775)
|
os.chmod(g.out_name, 0775)
|
||||||
f.write_bytes(g.buf.data, g.buf.len)
|
f.write_bytes(g.buf.data, g.buf.len)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module x64
|
module x64
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is unused right now, since binaries without sections
|
This file is unused right now, since binaries without sections
|
||||||
are generated.
|
are generated.
|
||||||
|
@ -11,26 +9,27 @@ are generated.
|
||||||
But it will be necessary once we have dynamic linking.
|
But it will be necessary once we have dynamic linking.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
enum SectionType {
|
enum SectionType {
|
||||||
null = 0
|
null
|
||||||
progbits = 1
|
=0progbits
|
||||||
symtab = 2
|
=1symtab
|
||||||
strtab = 3
|
=2strtab
|
||||||
rela = 4
|
=3rela
|
||||||
}
|
=4}
|
||||||
|
|
||||||
struct SectionConfig {
|
struct SectionConfig {
|
||||||
name string
|
name string
|
||||||
typ SectionType
|
typ SectionType
|
||||||
flags i64
|
flags i64
|
||||||
data voidptr
|
data voidptr
|
||||||
is_saa bool
|
is_saa bool
|
||||||
datalen i64
|
datalen i64
|
||||||
link int
|
link int
|
||||||
info int
|
info int
|
||||||
align i64
|
align i64
|
||||||
entsize i64
|
entsize i64
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) section_header(c SectionConfig) {
|
fn (g mut Gen) section_header(c SectionConfig) {
|
||||||
g.write32(g.sect_header_name_pos)
|
g.write32(g.sect_header_name_pos)
|
||||||
|
@ -38,15 +37,14 @@ fn (g mut Gen) section_header(c SectionConfig) {
|
||||||
g.write32(int(c.typ))
|
g.write32(int(c.typ))
|
||||||
g.write64(c.flags)
|
g.write64(c.flags)
|
||||||
g.write64(0) // sh_addr
|
g.write64(0) // sh_addr
|
||||||
g.write64(g.offset)// offset
|
g.write64(g.offset) // offset
|
||||||
g.offset += c.datalen+1
|
g.offset += c.datalen + 1
|
||||||
g.write64(c.datalen)
|
g.write64(c.datalen)
|
||||||
g.write32(c.link)
|
g.write32(c.link)
|
||||||
g.write32(c.info)
|
g.write32(c.info)
|
||||||
g.write64(c.align)
|
g.write64(c.align)
|
||||||
g.write64(c.entsize)
|
g.write64(c.entsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn genobj() {
|
fn genobj() {
|
||||||
/*
|
/*
|
||||||
|
@ -158,4 +156,4 @@ fn genobj() {
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module x64
|
module x64
|
||||||
|
|
||||||
pub struct Gen {
|
pub struct Gen {
|
||||||
out_name string
|
out_name string
|
||||||
mut:
|
mut:
|
||||||
buf []byte
|
buf []byte
|
||||||
sect_header_name_pos int
|
sect_header_name_pos int
|
||||||
offset i64
|
offset i64
|
||||||
str_pos []i64
|
str_pos []i64
|
||||||
strings []string // TODO use a map and don't duplicate strings
|
strings []string // TODO use a map and don't duplicate strings
|
||||||
file_size_pos i64
|
file_size_pos i64
|
||||||
main_fn_addr i64
|
main_fn_addr i64
|
||||||
code_start_pos i64 // location of the start of the assembly instructions
|
code_start_pos i64 // location of the start of the assembly instructions
|
||||||
fn_addr map[string]i64
|
fn_addr map[string]i64
|
||||||
//string_addr map[string]i64
|
// string_addr map[string]i64
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Register {
|
enum Register {
|
||||||
|
@ -39,7 +38,7 @@ enum Size {
|
||||||
|
|
||||||
pub fn new_gen(out_name string) &Gen {
|
pub fn new_gen(out_name string) &Gen {
|
||||||
return &Gen{
|
return &Gen{
|
||||||
sect_header_name_pos : 0
|
sect_header_name_pos: 0
|
||||||
buf: []
|
buf: []
|
||||||
out_name: out_name
|
out_name: out_name
|
||||||
}
|
}
|
||||||
|
@ -49,7 +48,6 @@ pub fn (g &Gen) pos() i64 {
|
||||||
return g.buf.len
|
return g.buf.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn (g mut Gen) write8(n int) {
|
fn (g mut Gen) write8(n int) {
|
||||||
// write 1 byte
|
// write 1 byte
|
||||||
g.buf << byte(n)
|
g.buf << byte(n)
|
||||||
|
@ -58,39 +56,39 @@ fn (g mut Gen) write8(n int) {
|
||||||
fn (g mut Gen) write16(n int) {
|
fn (g mut Gen) write16(n int) {
|
||||||
// write 2 bytes
|
// write 2 bytes
|
||||||
g.buf << byte(n)
|
g.buf << byte(n)
|
||||||
g.buf << byte(n >> 8)
|
g.buf << byte(n>>8)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) write32(n int) {
|
fn (g mut Gen) write32(n int) {
|
||||||
// write 4 bytes
|
// write 4 bytes
|
||||||
g.buf << byte(n)
|
g.buf << byte(n)
|
||||||
g.buf << byte(n >> 8)
|
g.buf << byte(n>>8)
|
||||||
g.buf << byte(n >> 16)
|
g.buf << byte(n>>16)
|
||||||
g.buf << byte(n >> 24)
|
g.buf << byte(n>>24)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) write64(n i64) {
|
fn (g mut Gen) write64(n i64) {
|
||||||
// write 8 bytes
|
// write 8 bytes
|
||||||
g.buf << byte(n)
|
g.buf << byte(n)
|
||||||
g.buf << byte(n >> 8)
|
g.buf << byte(n>>8)
|
||||||
g.buf << byte(n >> 16)
|
g.buf << byte(n>>16)
|
||||||
g.buf << byte(n >> 24)
|
g.buf << byte(n>>24)
|
||||||
g.buf << byte(n >> 32)
|
g.buf << byte(n>>32)
|
||||||
g.buf << byte(n >> 40)
|
g.buf << byte(n>>40)
|
||||||
g.buf << byte(n >> 48)
|
g.buf << byte(n>>48)
|
||||||
g.buf << byte(n >> 56)
|
g.buf << byte(n>>56)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) write64_at(n i64, at i64) {
|
fn (g mut Gen) write64_at(n i64, at i64) {
|
||||||
// write 8 bytes
|
// write 8 bytes
|
||||||
g.buf[at] = byte(n)
|
g.buf[at] = byte(n)
|
||||||
g.buf[at+1] = byte(n >> 8)
|
g.buf[at + 1] = byte(n>>8)
|
||||||
g.buf[at+2] = byte(n >> 16)
|
g.buf[at + 2] = byte(n>>16)
|
||||||
g.buf[at+3] = byte(n >> 24)
|
g.buf[at + 3] = byte(n>>24)
|
||||||
g.buf[at+4] = byte(n >> 32)
|
g.buf[at + 4] = byte(n>>32)
|
||||||
g.buf[at+5] = byte(n >> 40)
|
g.buf[at + 5] = byte(n>>40)
|
||||||
g.buf[at+6] = byte(n >> 48)
|
g.buf[at + 6] = byte(n>>48)
|
||||||
g.buf[at+7] = byte(n >> 56)
|
g.buf[at + 7] = byte(n>>56)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) write_string(s string) {
|
fn (g mut Gen) write_string(s string) {
|
||||||
|
@ -102,48 +100,61 @@ fn (g mut Gen) write_string(s string) {
|
||||||
fn (g mut Gen) inc(reg Register) {
|
fn (g mut Gen) inc(reg Register) {
|
||||||
g.write16(0xff49)
|
g.write16(0xff49)
|
||||||
match reg {
|
match reg {
|
||||||
.r12 { g.write8(0xc4) }
|
.r12 {
|
||||||
else { panic('unhandled inc $reg') }
|
g.write8(0xc4)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
panic('unhandled inc $reg')
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) cmp(reg Register, size Size, val i64) {
|
fn (g mut Gen) cmp(reg Register, size Size, val i64) {
|
||||||
g.write8(0x49)
|
g.write8(0x49)
|
||||||
// Second byte depends on the size of the value
|
// Second byte depends on the size of the value
|
||||||
match size {
|
match size {
|
||||||
._8 { g.write8(0x83) }
|
._8 {
|
||||||
._32 { g.write8(0x81) }
|
g.write8(0x83)
|
||||||
else { panic('unhandled cmp') }
|
}
|
||||||
}
|
._32 {
|
||||||
|
g.write8(0x81)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
panic('unhandled cmp')
|
||||||
|
}}
|
||||||
// Third byte depends on the register being compared to
|
// Third byte depends on the register being compared to
|
||||||
match reg {
|
match reg {
|
||||||
.r12 { g.write8(0xfc) }
|
.r12 {
|
||||||
else { panic('unhandled cmp') }
|
g.write8(0xfc)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
panic('unhandled cmp')
|
||||||
|
}}
|
||||||
g.write8(int(val))
|
g.write8(int(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abs(a i64) i64 { return if a < 0 { -a } else { a } }
|
fn abs(a i64) i64 {
|
||||||
|
return if a < 0 { -a } else { a }
|
||||||
|
}
|
||||||
|
|
||||||
fn (g mut Gen) jle(addr i64) {
|
fn (g mut Gen) jle(addr i64) {
|
||||||
// Calculate the relative offset to jump to
|
// Calculate the relative offset to jump to
|
||||||
// (`addr` is absolute address)
|
// (`addr` is absolute address)
|
||||||
offset := 0xff - int(abs(addr - g.buf.len))-1
|
offset := 0xff - int(abs(addr - g.buf.len)) - 1
|
||||||
g.write8(0x7e)
|
g.write8(0x7e)
|
||||||
g.write8(offset)
|
g.write8(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) jl(addr i64) {
|
fn (g mut Gen) jl(addr i64) {
|
||||||
offset := 0xff - int(abs(addr - g.buf.len))-1
|
offset := 0xff - int(abs(addr - g.buf.len)) - 1
|
||||||
g.write8(0x7c)
|
g.write8(0x7c)
|
||||||
g.write8(offset)
|
g.write8(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &Gen) abs_to_rel_addr(addr i64) int {
|
fn (g &Gen) abs_to_rel_addr(addr i64) int {
|
||||||
return int(abs(addr - g.buf.len))-1
|
return int(abs(addr - g.buf.len)) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) jmp (addr i64) {
|
fn (g mut Gen) jmp(addr i64) {
|
||||||
offset := 0xff - g.abs_to_rel_addr(addr)
|
offset := 0xff - g.abs_to_rel_addr(addr)
|
||||||
g.write8(0xe9)
|
g.write8(0xe9)
|
||||||
g.write8(offset)
|
g.write8(offset)
|
||||||
|
@ -155,15 +166,15 @@ fn (g mut Gen) mov64(reg Register, val i64) {
|
||||||
g.write8(0x48)
|
g.write8(0x48)
|
||||||
g.write8(0xbe)
|
g.write8(0xbe)
|
||||||
}
|
}
|
||||||
else { println('unhandled mov $reg') }
|
else {
|
||||||
}
|
println('unhandled mov $reg')
|
||||||
|
}}
|
||||||
g.write64(val)
|
g.write64(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) call(addr int) {
|
fn (g mut Gen) call(addr int) {
|
||||||
//rel := g.abs_to_rel_addr(addr)
|
// rel := g.abs_to_rel_addr(addr)
|
||||||
//rel := 0xffffffff - int(abs(addr - g.buf.len))-1
|
// rel := 0xffffffff - int(abs(addr - g.buf.len))-1
|
||||||
|
|
||||||
println('call addr=$addr rel_addr=$addr pos=$g.buf.len')
|
println('call addr=$addr rel_addr=$addr pos=$g.buf.len')
|
||||||
g.write8(0xe8)
|
g.write8(0xe8)
|
||||||
g.write32(addr)
|
g.write32(addr)
|
||||||
|
@ -198,13 +209,13 @@ pub fn (g mut Gen) save_main_fn_addr() {
|
||||||
|
|
||||||
pub fn (g mut Gen) gen_print(s string) {
|
pub fn (g mut Gen) gen_print(s string) {
|
||||||
g.strings << s + '\n'
|
g.strings << s + '\n'
|
||||||
//g.string_addr[s] = str_pos
|
// g.string_addr[s] = str_pos
|
||||||
g.mov(.eax, 1)
|
g.mov(.eax, 1)
|
||||||
g.mov(.edi, 1)
|
g.mov(.edi, 1)
|
||||||
str_pos := g.buf.len + 2
|
str_pos := g.buf.len + 2
|
||||||
g.str_pos << str_pos
|
g.str_pos << str_pos
|
||||||
g.mov64(.rsi, 0) //segment_start + 0x9f) // str pos // PLACEHOLDER
|
g.mov64(.rsi, 0) // segment_start + 0x9f) // str pos // PLACEHOLDER
|
||||||
g.mov(.edx, s.len+1) // len
|
g.mov(.edx, s.len + 1) // len
|
||||||
g.syscall()
|
g.syscall()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,22 +228,26 @@ pub fn (g mut Gen) gen_exit() {
|
||||||
|
|
||||||
fn (g mut Gen) mov(reg Register, val int) {
|
fn (g mut Gen) mov(reg Register, val int) {
|
||||||
match reg {
|
match reg {
|
||||||
.eax { g.write8(0xb8) }
|
.eax {
|
||||||
.edi { g.write8(0xbf) }
|
g.write8(0xb8)
|
||||||
.edx { g.write8(0xba) }
|
}
|
||||||
|
.edi {
|
||||||
|
g.write8(0xbf)
|
||||||
|
}
|
||||||
|
.edx {
|
||||||
|
g.write8(0xba)
|
||||||
|
}
|
||||||
.rsi {
|
.rsi {
|
||||||
g.write8(0x48)
|
g.write8(0x48)
|
||||||
g.write8(0xbe)
|
g.write8(0xbe)
|
||||||
}
|
}
|
||||||
.r12 {
|
.r12 {
|
||||||
g.write8(0x41)
|
g.write8(0x41)
|
||||||
g.write8(0xbc) // r11 is 0xbb etc
|
g.write8(0xbc) // r11 is 0xbb etc
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
panic('unhandled mov $reg')
|
panic('unhandled mov $reg')
|
||||||
}
|
}}
|
||||||
|
|
||||||
}
|
|
||||||
g.write32(val)
|
g.write32(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,4 +266,3 @@ pub fn (g mut Gen) call_fn(name string) {
|
||||||
println('call $name $addr')
|
println('call $name $addr')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
module filepath
|
module filepath
|
||||||
|
|
||||||
import(
|
import (
|
||||||
os
|
os
|
||||||
)
|
)
|
||||||
|
|
||||||
// return the extension in the file `path`
|
// return the extension in the file `path`
|
||||||
|
|
||||||
|
|
||||||
pub fn ext(path string) string {
|
pub fn ext(path string) string {
|
||||||
pos := path.last_index_byte(`.`)
|
pos := path.last_index_byte(`.`)
|
||||||
if pos != -1 {
|
if pos != -1 {
|
||||||
|
@ -17,16 +18,19 @@ pub fn ext(path string) string {
|
||||||
pub fn is_abs(path string) bool {
|
pub fn is_abs(path string) bool {
|
||||||
$if windows {
|
$if windows {
|
||||||
return path[0] == `/` || // incase we're in MingGW bash
|
return path[0] == `/` || // incase we're in MingGW bash
|
||||||
(path[0].is_letter() && path[1] == `:`)
|
(path[0].is_letter() && path[1] == `:`)
|
||||||
}
|
}
|
||||||
return path[0] == `/`
|
return path[0] == `/`
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass directories as parameters, returns path as string
|
// pass directories as parameters, returns path as string
|
||||||
// TODO use []string.join once ...string becomes "[]string"
|
// TODO use []string.join once ...string becomes "[]string"
|
||||||
pub fn join(base string, dirs ...string) string {
|
pub fn join(base string, dirs ...string) string {
|
||||||
mut result := []string
|
mut result := []string
|
||||||
result << base.trim_right('\\/')
|
result << base.trim_right('\\/')
|
||||||
for d in dirs { result << d }
|
for d in dirs {
|
||||||
return result.join( os.path_separator )
|
result << d
|
||||||
|
}
|
||||||
|
return result.join(os.path_separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
module os
|
module os
|
||||||
// (Must be realized in Syscall) (Must be specified)
|
// (Must be realized in Syscall) (Must be specified)
|
||||||
// File modes.
|
// File modes.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
O_RDONLY = 1 // open the file read-only.
|
O_RDONLY = 1 // open the file read-only.
|
||||||
O_WRONLY = 2 // open the file write-only.
|
O_WRONLY = 2 // open the file write-only.
|
||||||
|
|
465
vlib/os/os.v
465
vlib/os/os.v
|
@ -1,15 +1,12 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module os
|
module os
|
||||||
|
|
||||||
import filepath
|
import filepath
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h> // #include <signal.h>
|
||||||
//#include <signal.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct dirent {
|
struct dirent {
|
||||||
d_ino int
|
d_ino int
|
||||||
|
@ -26,13 +23,14 @@ struct C.dirent {
|
||||||
|
|
||||||
fn C.readdir(voidptr) C.dirent
|
fn C.readdir(voidptr) C.dirent
|
||||||
|
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
args = []string
|
args = []string
|
||||||
MAX_PATH = 4096
|
MAX_PATH = 4096
|
||||||
)
|
)
|
||||||
|
|
||||||
pub struct File {
|
pub struct File {
|
||||||
cfile voidptr // Using void* instead of FILE*
|
cfile voidptr // Using void* instead of FILE*
|
||||||
mut:
|
mut:
|
||||||
opened bool
|
opened bool
|
||||||
}
|
}
|
||||||
|
@ -43,30 +41,33 @@ struct FileInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct C.stat {
|
struct C.stat {
|
||||||
st_size int
|
st_size int
|
||||||
st_mode u32
|
st_mode u32
|
||||||
st_mtime int
|
st_mtime int
|
||||||
}
|
}
|
||||||
|
|
||||||
struct C.DIR {
|
struct C.DIR {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//struct C.dirent {
|
// struct C.dirent {
|
||||||
//d_name byteptr
|
// d_name byteptr
|
||||||
|
// }
|
||||||
//}
|
|
||||||
|
|
||||||
struct C.sigaction {
|
struct C.sigaction {
|
||||||
mut:
|
mut:
|
||||||
sa_mask int
|
sa_mask int
|
||||||
sa_sigaction int
|
sa_sigaction int
|
||||||
sa_flags int
|
sa_flags int
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.getline(voidptr, voidptr, voidptr) int
|
fn C.getline(voidptr, voidptr, voidptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.ftell(fp voidptr) int
|
fn C.ftell(fp voidptr) int
|
||||||
|
|
||||||
|
|
||||||
fn C.getenv(byteptr) &char
|
fn C.getenv(byteptr) &char
|
||||||
|
|
||||||
|
|
||||||
fn C.sigaction(int, voidptr, int)
|
fn C.sigaction(int, voidptr, int)
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ pub fn (f mut File) read_bytes(size int) []byte {
|
||||||
|
|
||||||
// read_bytes_at reads an amount of bytes at the given position in the file
|
// read_bytes_at reads an amount of bytes at the given position in the file
|
||||||
pub fn (f mut File) read_bytes_at(size, pos int) []byte {
|
pub fn (f mut File) read_bytes_at(size, pos int) []byte {
|
||||||
mut arr := [`0`].repeat(size)
|
mut arr := [`0`].repeat(size)
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
C.fseek(f.cfile, pos, C.SEEK_SET)
|
||||||
nreadbytes := C.fread(arr.data, 1, size, f.cfile)
|
nreadbytes := C.fread(arr.data, 1, size, f.cfile)
|
||||||
C.fseek(f.cfile, 0, C.SEEK_SET)
|
C.fseek(f.cfile, 0, C.SEEK_SET)
|
||||||
|
@ -96,8 +97,7 @@ pub fn read_bytes(path string) ?[]byte {
|
||||||
C.fseek(fp, 0, C.SEEK_END)
|
C.fseek(fp, 0, C.SEEK_END)
|
||||||
fsize := C.ftell(fp)
|
fsize := C.ftell(fp)
|
||||||
C.rewind(fp)
|
C.rewind(fp)
|
||||||
|
mut res := [`0`].repeat(fsize)
|
||||||
mut res := [`0`].repeat(fsize)
|
|
||||||
nr_read_elements := C.fread(res.data, fsize, 1, fp)
|
nr_read_elements := C.fread(res.data, fsize, 1, fp)
|
||||||
C.fclose(fp)
|
C.fclose(fp)
|
||||||
return res[0..nr_read_elements * fsize]
|
return res[0..nr_read_elements * fsize]
|
||||||
|
@ -118,12 +118,13 @@ pub fn read_file(path string) ?string {
|
||||||
C.fread(str, fsize, 1, fp)
|
C.fread(str, fsize, 1, fp)
|
||||||
C.fclose(fp)
|
C.fclose(fp)
|
||||||
str[fsize] = 0
|
str[fsize] = 0
|
||||||
return string(str, fsize)
|
return string(str,fsize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// file_size returns the size of the file located in `path`.
|
// file_size returns the size of the file located in `path`.
|
||||||
pub fn file_size(path string) int {
|
pub fn file_size(path string) int {
|
||||||
mut s := C.stat{}
|
mut s := C.stat{
|
||||||
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
C._wstat(path.to_wide(), voidptr(&s))
|
C._wstat(path.to_wide(), voidptr(&s))
|
||||||
} $else {
|
} $else {
|
||||||
|
@ -141,18 +142,17 @@ pub fn mv(old, new string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.CopyFile(&u32, &u32, int) int
|
fn C.CopyFile(&u32, &u32, int) int
|
||||||
|
|
||||||
// TODO implement actual cp for linux
|
// TODO implement actual cp for linux
|
||||||
pub fn cp(old, new string) ?bool {
|
pub fn cp(old, new string) ?bool {
|
||||||
$if windows {
|
$if windows {
|
||||||
_old := old.replace('/', '\\')
|
_old := old.replace('/', '\\')
|
||||||
_new := new.replace('/', '\\')
|
_new := new.replace('/', '\\')
|
||||||
C.CopyFile(_old.to_wide(), _new.to_wide(), false)
|
C.CopyFile(_old.to_wide(), _new.to_wide(), false)
|
||||||
|
|
||||||
result := C.GetLastError()
|
result := C.GetLastError()
|
||||||
if result == 0 {
|
if result == 0 {
|
||||||
return true
|
return true
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return error_with_code('failed to copy $old to $new', int(result))
|
return error_with_code('failed to copy $old to $new', int(result))
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
|
@ -161,19 +161,15 @@ pub fn cp(old, new string) ?bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool{
|
pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool {
|
||||||
source_path := os.realpath( osource_path )
|
source_path := os.realpath(osource_path)
|
||||||
dest_path := os.realpath( odest_path )
|
dest_path := os.realpath(odest_path)
|
||||||
if !os.exists(source_path) {
|
if !os.exists(source_path) {
|
||||||
return error('Source path doesn\'t exist')
|
return error("Source path doesn\'t exist")
|
||||||
}
|
}
|
||||||
//single file copy
|
// single file copy
|
||||||
if !os.is_dir(source_path) {
|
if !os.is_dir(source_path) {
|
||||||
adjasted_path := if os.is_dir(dest_path) {
|
adjasted_path := if os.is_dir(dest_path) { filepath.join(dest_path,os.filename(source_path)) } else { dest_path }
|
||||||
filepath.join(dest_path, os.filename(source_path))
|
|
||||||
} else {
|
|
||||||
dest_path
|
|
||||||
}
|
|
||||||
if os.exists(adjasted_path) {
|
if os.exists(adjasted_path) {
|
||||||
if overwrite {
|
if overwrite {
|
||||||
os.rm(adjasted_path)
|
os.rm(adjasted_path)
|
||||||
|
@ -182,20 +178,26 @@ pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool{
|
||||||
return error('Destination file path already exist')
|
return error('Destination file path already exist')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os.cp(source_path, adjasted_path) or { return error(err) }
|
os.cp(source_path, adjasted_path)or{
|
||||||
|
return error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !os.is_dir(dest_path) {
|
if !os.is_dir(dest_path) {
|
||||||
return error('Destination path is not a valid directory')
|
return error('Destination path is not a valid directory')
|
||||||
}
|
}
|
||||||
files := os.ls(source_path) or { return error(err) }
|
files := os.ls(source_path)or{
|
||||||
|
return error(err)
|
||||||
|
}
|
||||||
for file in files {
|
for file in files {
|
||||||
sp := filepath.join(source_path, file)
|
sp := filepath.join(source_path,file)
|
||||||
dp := filepath.join(dest_path, file)
|
dp := filepath.join(dest_path,file)
|
||||||
if os.is_dir(sp) {
|
if os.is_dir(sp) {
|
||||||
os.mkdir(dp) or { panic(err) }
|
os.mkdir(dp)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cp_r(sp, dp, overwrite) or {
|
cp_r(sp, dp, overwrite)or{
|
||||||
os.rmdir(dp)
|
os.rmdir(dp)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -206,7 +208,9 @@ pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool{
|
||||||
// mv_by_cp first copies the source file, and if it is copied successfully, deletes the source file.
|
// mv_by_cp first copies the source file, and if it is copied successfully, deletes the source file.
|
||||||
// mv_by_cp may be used when you are not sure that the source and target are on the same mount/partition.
|
// mv_by_cp may be used when you are not sure that the source and target are on the same mount/partition.
|
||||||
pub fn mv_by_cp(source string, target string) ?bool {
|
pub fn mv_by_cp(source string, target string) ?bool {
|
||||||
os.cp(source, target) or { return error(err) }
|
os.cp(source, target)or{
|
||||||
|
return error(err)
|
||||||
|
}
|
||||||
os.rm(source)
|
os.rm(source)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -224,13 +228,11 @@ pub fn read_lines(path string) ?[]string {
|
||||||
mut res := []string
|
mut res := []string
|
||||||
mut buf_len := 1024
|
mut buf_len := 1024
|
||||||
mut buf := malloc(buf_len)
|
mut buf := malloc(buf_len)
|
||||||
|
|
||||||
mode := 'rb'
|
mode := 'rb'
|
||||||
mut fp := vfopen(path, mode)
|
mut fp := vfopen(path, mode)
|
||||||
if isnil(fp) {
|
if isnil(fp) {
|
||||||
return error('read_lines() failed to open file "$path"')
|
return error('read_lines() failed to open file "$path"')
|
||||||
}
|
}
|
||||||
|
|
||||||
mut buf_index := 0
|
mut buf_index := 0
|
||||||
for C.fgets(buf + buf_index, buf_len - buf_index, fp) != 0 {
|
for C.fgets(buf + buf_index, buf_len - buf_index, fp) != 0 {
|
||||||
len := vstrlen(buf)
|
len := vstrlen(buf)
|
||||||
|
@ -257,7 +259,7 @@ pub fn read_lines(path string) ?[]string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_ulines(path string) ?[]ustring {
|
fn read_ulines(path string) ?[]ustring {
|
||||||
lines := read_lines(path) or {
|
lines := read_lines(path)or{
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// mut ulines := new_array(0, lines.len, sizeof(ustring))
|
// mut ulines := new_array(0, lines.len, sizeof(ustring))
|
||||||
|
@ -270,16 +272,17 @@ fn read_ulines(path string) ?[]ustring {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(path string) ?File {
|
pub fn open(path string) ?File {
|
||||||
mut file := File{}
|
mut file := File{
|
||||||
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
wpath := path.to_wide()
|
wpath := path.to_wide()
|
||||||
mode := 'rb'
|
mode := 'rb'
|
||||||
file = File {
|
file = File{
|
||||||
cfile: C._wfopen(wpath, mode.to_wide())
|
cfile: C._wfopen(wpath, mode.to_wide())
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
cpath := path.str
|
cpath := path.str
|
||||||
file = File {
|
file = File{
|
||||||
cfile: C.fopen(charptr(cpath), 'rb')
|
cfile: C.fopen(charptr(cpath), 'rb')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,16 +295,17 @@ pub fn open(path string) ?File {
|
||||||
|
|
||||||
// create creates a file at a specified location and returns a writable `File` object.
|
// create creates a file at a specified location and returns a writable `File` object.
|
||||||
pub fn create(path string) ?File {
|
pub fn create(path string) ?File {
|
||||||
mut file := File{}
|
mut file := File{
|
||||||
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
wpath := path.replace('/', '\\').to_wide()
|
wpath := path.replace('/', '\\').to_wide()
|
||||||
mode := 'wb'
|
mode := 'wb'
|
||||||
file = File {
|
file = File{
|
||||||
cfile: C._wfopen(wpath, mode.to_wide())
|
cfile: C._wfopen(wpath, mode.to_wide())
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
cpath := path.str
|
cpath := path.str
|
||||||
file = File {
|
file = File{
|
||||||
cfile: C.fopen(charptr(cpath), 'wb')
|
cfile: C.fopen(charptr(cpath), 'wb')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,16 +317,17 @@ pub fn create(path string) ?File {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_append(path string) ?File {
|
pub fn open_append(path string) ?File {
|
||||||
mut file := File{}
|
mut file := File{
|
||||||
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
wpath := path.replace('/', '\\').to_wide()
|
wpath := path.replace('/', '\\').to_wide()
|
||||||
mode := 'ab'
|
mode := 'ab'
|
||||||
file = File {
|
file = File{
|
||||||
cfile: C._wfopen(wpath, mode.to_wide())
|
cfile: C._wfopen(wpath, mode.to_wide())
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
cpath := path.str
|
cpath := path.str
|
||||||
file = File {
|
file = File{
|
||||||
cfile: C.fopen(charptr(cpath), 'ab')
|
cfile: C.fopen(charptr(cpath), 'ab')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,7 +342,6 @@ pub fn (f mut File) write(s string) {
|
||||||
C.fputs(s.str, f.cfile)
|
C.fputs(s.str, f.cfile)
|
||||||
// C.fwrite(s.str, 1, s.len, f.cfile)
|
// C.fwrite(s.str, 1, s.len, f.cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert any value to []byte (LittleEndian) and write it
|
// convert any value to []byte (LittleEndian) and write it
|
||||||
// for example if we have write(7, 4), "07 00 00 00" gets written
|
// for example if we have write(7, 4), "07 00 00 00" gets written
|
||||||
// write(0x1234, 2) => "34 12"
|
// write(0x1234, 2) => "34 12"
|
||||||
|
@ -352,7 +356,9 @@ pub fn (f mut File) write_bytes_at(data voidptr, size, pos int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (f mut File) writeln(s string) {
|
pub fn (f mut File) writeln(s string) {
|
||||||
if !f.opened { return }
|
if !f.opened {
|
||||||
|
return
|
||||||
|
}
|
||||||
// C.fwrite(s.str, 1, s.len, f.cfile)
|
// C.fwrite(s.str, 1, s.len, f.cfile)
|
||||||
// ss := s.clone()
|
// ss := s.clone()
|
||||||
// TODO perf
|
// TODO perf
|
||||||
|
@ -362,25 +368,29 @@ pub fn (f mut File) writeln(s string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (f mut File) flush() {
|
pub fn (f mut File) flush() {
|
||||||
if !f.opened { return }
|
if !f.opened {
|
||||||
|
return
|
||||||
|
}
|
||||||
C.fflush(f.cfile)
|
C.fflush(f.cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (f mut File) close() {
|
pub fn (f mut File) close() {
|
||||||
if !f.opened { return }
|
if !f.opened {
|
||||||
|
return
|
||||||
|
}
|
||||||
f.opened = false
|
f.opened = false
|
||||||
C.fflush(f.cfile)
|
C.fflush(f.cfile)
|
||||||
C.fclose(f.cfile)
|
C.fclose(f.cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// system starts the specified command, waits for it to complete, and returns its code.
|
// system starts the specified command, waits for it to complete, and returns its code.
|
||||||
fn vpopen(path string) voidptr {//*C.FILE {
|
fn vpopen(path string) voidptr {
|
||||||
|
// *C.FILE {
|
||||||
$if windows {
|
$if windows {
|
||||||
mode := 'rb'
|
mode := 'rb'
|
||||||
wpath := path.to_wide()
|
wpath := path.to_wide()
|
||||||
return C._wpopen(wpath, mode.to_wide())
|
return C._wpopen(wpath, mode.to_wide())
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
cpath := path.str
|
cpath := path.str
|
||||||
return C.popen(cpath, 'r')
|
return C.popen(cpath, 'r')
|
||||||
}
|
}
|
||||||
|
@ -388,29 +398,28 @@ fn vpopen(path string) voidptr {//*C.FILE {
|
||||||
|
|
||||||
fn posix_wait4_to_exit_status(waitret int) (int,bool) {
|
fn posix_wait4_to_exit_status(waitret int) (int,bool) {
|
||||||
$if windows {
|
$if windows {
|
||||||
return waitret, false
|
return waitret,false
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
mut ret := 0
|
mut ret := 0
|
||||||
mut is_signaled := true
|
mut is_signaled := true
|
||||||
// (see man system, man 2 waitpid: C macro WEXITSTATUS section)
|
// (see man system, man 2 waitpid: C macro WEXITSTATUS section)
|
||||||
if C.WIFEXITED( waitret ) {
|
if C.WIFEXITED(waitret) {
|
||||||
ret = C.WEXITSTATUS( waitret )
|
ret = C.WEXITSTATUS(waitret)
|
||||||
is_signaled = false
|
is_signaled = false
|
||||||
} else if C.WIFSIGNALED( waitret ){
|
}
|
||||||
ret = C.WTERMSIG( waitret )
|
else if C.WIFSIGNALED(waitret) {
|
||||||
|
ret = C.WTERMSIG(waitret)
|
||||||
is_signaled = true
|
is_signaled = true
|
||||||
}
|
}
|
||||||
return ret , is_signaled
|
return ret,is_signaled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vpclose(f voidptr) int {
|
fn vpclose(f voidptr) int {
|
||||||
$if windows {
|
$if windows {
|
||||||
return C._pclose(f)
|
return C._pclose(f)
|
||||||
}
|
} $else {
|
||||||
$else {
|
ret,_ := posix_wait4_to_exit_status(C.pclose(f))
|
||||||
ret , _ := posix_wait4_to_exit_status(C.pclose(f))
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,16 +427,15 @@ fn vpclose(f voidptr) int {
|
||||||
pub struct Result {
|
pub struct Result {
|
||||||
pub:
|
pub:
|
||||||
exit_code int
|
exit_code int
|
||||||
output string
|
output string
|
||||||
//stderr string // TODO
|
// stderr string // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// `system` works like `exec()`, but only returns a return code.
|
// `system` works like `exec()`, but only returns a return code.
|
||||||
pub fn system(cmd string) int {
|
pub fn system(cmd string) int {
|
||||||
//if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
|
// if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
|
||||||
// TODO remove panic
|
// TODO remove panic
|
||||||
//panic(';, &&, || and \\n are not allowed in shell commands')
|
// panic(';, &&, || and \\n are not allowed in shell commands')
|
||||||
//}
|
// }
|
||||||
mut ret := 0
|
mut ret := 0
|
||||||
$if windows {
|
$if windows {
|
||||||
// overcome bug in system & _wsystem (cmd) when first char is quote `"`
|
// overcome bug in system & _wsystem (cmd) when first char is quote `"`
|
||||||
|
@ -439,11 +447,10 @@ pub fn system(cmd string) int {
|
||||||
if ret == -1 {
|
if ret == -1 {
|
||||||
print_c_errno()
|
print_c_errno()
|
||||||
}
|
}
|
||||||
|
|
||||||
$if !windows {
|
$if !windows {
|
||||||
pret , is_signaled := posix_wait4_to_exit_status( ret )
|
pret,is_signaled := posix_wait4_to_exit_status(ret)
|
||||||
if is_signaled {
|
if is_signaled {
|
||||||
println('Terminated by signal ${ret:2d} (' + sigint_to_signal_name(pret) + ')' )
|
println('Terminated by signal ${ret:2d} (' + sigint_to_signal_name(pret) + ')')
|
||||||
}
|
}
|
||||||
ret = pret
|
ret = pret
|
||||||
}
|
}
|
||||||
|
@ -453,35 +460,77 @@ pub fn system(cmd string) int {
|
||||||
pub fn sigint_to_signal_name(si int) string {
|
pub fn sigint_to_signal_name(si int) string {
|
||||||
// POSIX signals:
|
// POSIX signals:
|
||||||
match si {
|
match si {
|
||||||
1 {return 'SIGHUP'}
|
1 {
|
||||||
2 {return 'SIGINT'}
|
return 'SIGHUP'
|
||||||
3 {return 'SIGQUIT'}
|
}
|
||||||
4 {return 'SIGILL'}
|
2 {
|
||||||
6 {return 'SIGABRT'}
|
return 'SIGINT'
|
||||||
8 {return 'SIGFPE'}
|
}
|
||||||
9 {return 'SIGKILL'}
|
3 {
|
||||||
11 {return 'SIGSEGV'}
|
return 'SIGQUIT'
|
||||||
13 {return 'SIGPIPE'}
|
}
|
||||||
14 {return 'SIGALRM'}
|
4 {
|
||||||
15 {return 'SIGTERM'}
|
return 'SIGILL'
|
||||||
else { }
|
}
|
||||||
}
|
6 {
|
||||||
|
return 'SIGABRT'
|
||||||
|
}
|
||||||
|
8 {
|
||||||
|
return 'SIGFPE'
|
||||||
|
}
|
||||||
|
9 {
|
||||||
|
return 'SIGKILL'
|
||||||
|
}
|
||||||
|
11 {
|
||||||
|
return 'SIGSEGV'
|
||||||
|
}
|
||||||
|
13 {
|
||||||
|
return 'SIGPIPE'
|
||||||
|
}
|
||||||
|
14 {
|
||||||
|
return 'SIGALRM'
|
||||||
|
}
|
||||||
|
15 {
|
||||||
|
return 'SIGTERM'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
}}
|
||||||
$if linux {
|
$if linux {
|
||||||
// From `man 7 signal` on linux:
|
// From `man 7 signal` on linux:
|
||||||
match si {
|
match si {
|
||||||
30,10,16{ return 'SIGUSR1'}
|
30, 10, 16 {
|
||||||
31,12,17{ return 'SIGUSR2'}
|
return 'SIGUSR1'
|
||||||
20,17,18{ return 'SIGCHLD'}
|
}
|
||||||
19,18,25{ return 'SIGCONT'}
|
31, 12, 17 {
|
||||||
17,19,23{ return 'SIGSTOP'}
|
return 'SIGUSR2'
|
||||||
18,20,24{ return 'SIGTSTP'}
|
}
|
||||||
21,21,26{ return 'SIGTTIN'}
|
20, 17, 18 {
|
||||||
22,22,27{ return 'SIGTTOU'}
|
return 'SIGCHLD'
|
||||||
///////////////////////////////
|
}
|
||||||
5{ return 'SIGTRAP'}
|
19, 18, 25 {
|
||||||
7{ return 'SIGBUS' }
|
return 'SIGCONT'
|
||||||
else {}
|
}
|
||||||
}
|
17, 19, 23 {
|
||||||
|
return 'SIGSTOP'
|
||||||
|
}
|
||||||
|
18, 20, 24 {
|
||||||
|
return 'SIGTSTP'
|
||||||
|
}
|
||||||
|
21, 21, 26 {
|
||||||
|
return 'SIGTTIN'
|
||||||
|
}
|
||||||
|
22, 22, 27 {
|
||||||
|
return 'SIGTTOU'
|
||||||
|
}
|
||||||
|
// /////////////////////////////
|
||||||
|
5 {
|
||||||
|
return 'SIGTRAP'
|
||||||
|
}
|
||||||
|
7 {
|
||||||
|
return 'SIGBUS'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
return 'unknown'
|
return 'unknown'
|
||||||
}
|
}
|
||||||
|
@ -500,7 +549,7 @@ pub fn getenv(key string) string {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
// NB: C.getenv *requires* that the result be copied.
|
// NB: C.getenv *requires* that the result be copied.
|
||||||
return cstring_to_vstring( byteptr(s) )
|
return cstring_to_vstring(byteptr(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +580,7 @@ pub fn exists(path string) bool {
|
||||||
p := path.replace('/', '\\')
|
p := path.replace('/', '\\')
|
||||||
return C._waccess(p.to_wide(), 0) != -1
|
return C._waccess(p.to_wide(), 0) != -1
|
||||||
} $else {
|
} $else {
|
||||||
return C.access(path.str, 0 ) != -1
|
return C.access(path.str, 0) != -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,30 +593,24 @@ pub fn file_exists(_path string) bool {
|
||||||
pub fn rm(path string) {
|
pub fn rm(path string) {
|
||||||
$if windows {
|
$if windows {
|
||||||
C._wremove(path.to_wide())
|
C._wremove(path.to_wide())
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
C.remove(path.str)
|
C.remove(path.str)
|
||||||
}
|
}
|
||||||
// C.unlink(path.cstr())
|
// C.unlink(path.cstr())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// rmdir removes a specified directory.
|
// rmdir removes a specified directory.
|
||||||
pub fn rmdir(path string) {
|
pub fn rmdir(path string) {
|
||||||
$if !windows {
|
$if !windows {
|
||||||
C.rmdir(path.str)
|
C.rmdir(path.str)
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
C.RemoveDirectory(path.to_wide())
|
C.RemoveDirectory(path.to_wide())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn print_c_errno() {
|
fn print_c_errno() {
|
||||||
//C.printf('errno=%d err="%s"\n', C.errno, C.strerror(C.errno))
|
// C.printf('errno=%d err="%s"\n', C.errno, C.strerror(C.errno))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn ext(path string) string {
|
pub fn ext(path string) string {
|
||||||
pos := path.last_index('.') or {
|
pos := path.last_index('.') or {
|
||||||
return ''
|
return ''
|
||||||
|
@ -575,7 +618,6 @@ pub fn ext(path string) string {
|
||||||
return path[pos..]
|
return path[pos..]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// dir returns all but the last element of path, typically the path's directory.
|
// dir returns all but the last element of path, typically the path's directory.
|
||||||
pub fn dir(path string) string {
|
pub fn dir(path string) string {
|
||||||
if path == '.' {
|
if path == '.' {
|
||||||
|
@ -594,12 +636,11 @@ fn path_sans_ext(path string) string {
|
||||||
return path[..pos]
|
return path[..pos]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn basedir(path string) string {
|
pub fn basedir(path string) string {
|
||||||
pos := path.last_index(path_separator) or {
|
pos := path.last_index(path_separator) or {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
return path[..pos ] // NB: *without* terminating /
|
return path[..pos] // NB: *without* terminating /
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filename(path string) string {
|
pub fn filename(path string) string {
|
||||||
|
@ -608,53 +649,54 @@ pub fn filename(path string) string {
|
||||||
|
|
||||||
// get_line returns a one-line string from stdin
|
// get_line returns a one-line string from stdin
|
||||||
pub fn get_line() string {
|
pub fn get_line() string {
|
||||||
str := get_raw_line()
|
str := get_raw_line()
|
||||||
$if windows {
|
$if windows {
|
||||||
return str.trim_right('\r\n')
|
return str.trim_right('\r\n')
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
return str.trim_right('\n')
|
return str.trim_right('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_raw_line returns a one-line string from stdin along with '\n' if there is any
|
// get_raw_line returns a one-line string from stdin along with '\n' if there is any
|
||||||
pub fn get_raw_line() string {
|
pub fn get_raw_line() string {
|
||||||
$if windows {
|
$if windows {
|
||||||
max_line_chars := 256
|
max_line_chars := 256
|
||||||
buf := malloc(max_line_chars*2)
|
buf := malloc(max_line_chars * 2)
|
||||||
if is_atty(0) > 0 {
|
if is_atty(0) > 0 {
|
||||||
h_input := C.GetStdHandle(STD_INPUT_HANDLE)
|
h_input := C.GetStdHandle(STD_INPUT_HANDLE)
|
||||||
mut nr_chars := u32(0)
|
mut nr_chars := u32(0)
|
||||||
C.ReadConsole(h_input, buf, max_line_chars * 2, voidptr(&nr_chars), 0)
|
C.ReadConsole(h_input, buf, max_line_chars * 2, voidptr(&nr_chars), 0)
|
||||||
return string_from_wide2(&u16(buf), int(nr_chars))
|
return string_from_wide2(&u16(buf), int(nr_chars))
|
||||||
}
|
}
|
||||||
res := C.fgetws(&u16(buf), max_line_chars, C.stdin )
|
res := C.fgetws(&u16(buf), max_line_chars, C.stdin)
|
||||||
len := C.wcslen(&u16(buf))
|
len := C.wcslen(&u16(buf))
|
||||||
if !isnil(res) { return string_from_wide2( &u16(buf), len ) }
|
if !isnil(res) {
|
||||||
return ''
|
return string_from_wide2(&u16(buf), len)
|
||||||
} $else {
|
}
|
||||||
max := size_t(256)
|
return ''
|
||||||
buf := charptr(malloc(int(max)))
|
} $else {
|
||||||
nr_chars := C.getline(&buf, &max, stdin)
|
max := size_t(256)
|
||||||
if nr_chars == 0 {
|
buf := charptr(malloc(int(max)))
|
||||||
return ''
|
nr_chars := C.getline(&buf, &max, stdin)
|
||||||
}
|
if nr_chars == 0 {
|
||||||
return string(byteptr(buf), nr_chars)
|
return ''
|
||||||
}
|
}
|
||||||
|
return string(byteptr(buf),nr_chars)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_lines() []string {
|
pub fn get_lines() []string {
|
||||||
mut line := ''
|
mut line := ''
|
||||||
mut inputstr := []string
|
mut inputstr := []string
|
||||||
for {
|
for {
|
||||||
line = get_line()
|
line = get_line()
|
||||||
if(line.len <= 0) {
|
if (line.len <= 0) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
line = line.trim_space()
|
line = line.trim_space()
|
||||||
inputstr << line
|
inputstr << line
|
||||||
}
|
}
|
||||||
return inputstr
|
return inputstr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_lines_joined() string {
|
pub fn get_lines_joined() string {
|
||||||
|
@ -694,7 +736,7 @@ pub fn user_os() string {
|
||||||
$if dragonfly {
|
$if dragonfly {
|
||||||
return 'dragonfly'
|
return 'dragonfly'
|
||||||
}
|
}
|
||||||
$if android{
|
$if android {
|
||||||
return 'android'
|
return 'android'
|
||||||
}
|
}
|
||||||
$if solaris {
|
$if solaris {
|
||||||
|
@ -726,7 +768,7 @@ pub fn home_dir() string {
|
||||||
|
|
||||||
// write_file writes `text` data to a file in `path`.
|
// write_file writes `text` data to a file in `path`.
|
||||||
pub fn write_file(path, text string) {
|
pub fn write_file(path, text string) {
|
||||||
mut f := os.create(path) or {
|
mut f := os.create(path)or{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.write(text)
|
f.write(text)
|
||||||
|
@ -746,7 +788,8 @@ pub fn on_segfault(f voidptr) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
$if macos {
|
$if macos {
|
||||||
mut sa := C.sigaction{}
|
mut sa := C.sigaction{
|
||||||
|
}
|
||||||
C.memset(&sa, 0, sizeof(sigaction))
|
C.memset(&sa, 0, sizeof(sigaction))
|
||||||
C.sigemptyset(&sa.sa_mask)
|
C.sigemptyset(&sa.sa_mask)
|
||||||
sa.sa_sigaction = f
|
sa.sa_sigaction = f
|
||||||
|
@ -756,10 +799,12 @@ pub fn on_segfault(f voidptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.getpid() int
|
fn C.getpid() int
|
||||||
fn C.proc_pidpath (int, byteptr, int) int
|
|
||||||
|
|
||||||
|
fn C.proc_pidpath(int, byteptr, int) int
|
||||||
|
|
||||||
|
|
||||||
fn C.readlink() int
|
fn C.readlink() int
|
||||||
|
|
||||||
|
|
||||||
// executable returns the path name of the executable that started the current
|
// executable returns the path name of the executable that started the current
|
||||||
// process.
|
// process.
|
||||||
pub fn executable() string {
|
pub fn executable() string {
|
||||||
|
@ -774,15 +819,15 @@ pub fn executable() string {
|
||||||
}
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
max := 512
|
max := 512
|
||||||
mut result := &u16(calloc(max*2)) // MAX_PATH * sizeof(wchar_t)
|
mut result := &u16(calloc(max * 2)) // MAX_PATH * sizeof(wchar_t)
|
||||||
len := C.GetModuleFileName( 0, result, max )
|
len := C.GetModuleFileName(0, result, max)
|
||||||
return string_from_wide2(result, len)
|
return string_from_wide2(result, len)
|
||||||
}
|
}
|
||||||
$if macos {
|
$if macos {
|
||||||
mut result := calloc(MAX_PATH)
|
mut result := calloc(MAX_PATH)
|
||||||
pid := C.getpid()
|
pid := C.getpid()
|
||||||
ret := proc_pidpath (pid, result, MAX_PATH)
|
ret := proc_pidpath(pid, result, MAX_PATH)
|
||||||
if ret <= 0 {
|
if ret <= 0 {
|
||||||
eprintln('os.executable() failed at calling proc_pidpath with pid: $pid . proc_pidpath returned $ret ')
|
eprintln('os.executable() failed at calling proc_pidpath with pid: $pid . proc_pidpath returned $ret ')
|
||||||
return os.args[0]
|
return os.args[0]
|
||||||
}
|
}
|
||||||
|
@ -790,7 +835,7 @@ pub fn executable() string {
|
||||||
}
|
}
|
||||||
$if freebsd {
|
$if freebsd {
|
||||||
mut result := calloc(MAX_PATH)
|
mut result := calloc(MAX_PATH)
|
||||||
mib := [1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1]
|
mib := [1/* CTL_KERN */, 14/* KERN_PROC */, 12/* KERN_PROC_PATHNAME */, -1]
|
||||||
size := MAX_PATH
|
size := MAX_PATH
|
||||||
C.sysctl(mib.data, 4, result, &size, 0, 0)
|
C.sysctl(mib.data, 4, result, &size, 0, 0)
|
||||||
return string(result)
|
return string(result)
|
||||||
|
@ -806,21 +851,21 @@ pub fn executable() string {
|
||||||
}
|
}
|
||||||
$if netbsd {
|
$if netbsd {
|
||||||
mut result := calloc(MAX_PATH)
|
mut result := calloc(MAX_PATH)
|
||||||
count := int(C.readlink('/proc/curproc/exe', result, MAX_PATH ))
|
count := int(C.readlink('/proc/curproc/exe', result, MAX_PATH))
|
||||||
if count < 0 {
|
if count < 0 {
|
||||||
eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path')
|
eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path')
|
||||||
return os.args[0]
|
return os.args[0]
|
||||||
}
|
}
|
||||||
return string(result, count)
|
return string(result,count)
|
||||||
}
|
}
|
||||||
$if dragonfly {
|
$if dragonfly {
|
||||||
mut result := calloc(MAX_PATH)
|
mut result := calloc(MAX_PATH)
|
||||||
count := int(C.readlink('/proc/curproc/file', result, MAX_PATH ))
|
count := int(C.readlink('/proc/curproc/file', result, MAX_PATH))
|
||||||
if count < 0 {
|
if count < 0 {
|
||||||
eprintln('os.executable() failed at reading /proc/curproc/file to get exe path')
|
eprintln('os.executable() failed at reading /proc/curproc/file to get exe path')
|
||||||
return os.args[0]
|
return os.args[0]
|
||||||
}
|
}
|
||||||
return string(result, count)
|
return string(result,count)
|
||||||
}
|
}
|
||||||
return os.args[0]
|
return os.args[0]
|
||||||
}
|
}
|
||||||
|
@ -828,9 +873,8 @@ pub fn executable() string {
|
||||||
[deprecated]
|
[deprecated]
|
||||||
pub fn dir_exists(path string) bool {
|
pub fn dir_exists(path string) bool {
|
||||||
panic('use os.is_dir()')
|
panic('use os.is_dir()')
|
||||||
//return false
|
// return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_dir returns a boolean indicating whether the given path is a directory.
|
// is_dir returns a boolean indicating whether the given path is a directory.
|
||||||
pub fn is_dir(path string) bool {
|
pub fn is_dir(path string) bool {
|
||||||
$if windows {
|
$if windows {
|
||||||
|
@ -843,9 +887,9 @@ pub fn is_dir(path string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
} $else {
|
||||||
$else {
|
statbuf := C.stat{
|
||||||
statbuf := C.stat{}
|
}
|
||||||
if C.stat(path.str, &statbuf) != 0 {
|
if C.stat(path.str, &statbuf) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -859,7 +903,8 @@ pub fn is_link(path string) bool {
|
||||||
$if windows {
|
$if windows {
|
||||||
return false // TODO
|
return false // TODO
|
||||||
} $else {
|
} $else {
|
||||||
statbuf := C.stat{}
|
statbuf := C.stat{
|
||||||
|
}
|
||||||
if C.lstat(path.str, &statbuf) != 0 {
|
if C.lstat(path.str, &statbuf) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -871,8 +916,7 @@ pub fn is_link(path string) bool {
|
||||||
pub fn chdir(path string) {
|
pub fn chdir(path string) {
|
||||||
$if windows {
|
$if windows {
|
||||||
C._wchdir(path.to_wide())
|
C._wchdir(path.to_wide())
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
C.chdir(path.str)
|
C.chdir(path.str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -881,13 +925,12 @@ pub fn chdir(path string) {
|
||||||
pub fn getwd() string {
|
pub fn getwd() string {
|
||||||
$if windows {
|
$if windows {
|
||||||
max := 512 // MAX_PATH * sizeof(wchar_t)
|
max := 512 // MAX_PATH * sizeof(wchar_t)
|
||||||
buf := &u16(calloc(max*2))
|
buf := &u16(calloc(max * 2))
|
||||||
if C._wgetcwd(buf, max) == 0 {
|
if C._wgetcwd(buf, max) == 0 {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
return string_from_wide(buf)
|
return string_from_wide(buf)
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
buf := calloc(512)
|
buf := calloc(512)
|
||||||
if C.getcwd(buf, 512) == 0 {
|
if C.getcwd(buf, 512) == 0 {
|
||||||
return ''
|
return ''
|
||||||
|
@ -899,7 +942,7 @@ pub fn getwd() string {
|
||||||
// Returns the full absolute path for fpath, with all relative ../../, symlinks and so on resolved.
|
// Returns the full absolute path for fpath, with all relative ../../, symlinks and so on resolved.
|
||||||
// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html
|
// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html
|
||||||
// Also https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
|
// Also https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
|
||||||
// and https://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html
|
// and https://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html
|
||||||
// NB: this particular rabbit hole is *deep* ...
|
// NB: this particular rabbit hole is *deep* ...
|
||||||
pub fn realpath(fpath string) string {
|
pub fn realpath(fpath string) string {
|
||||||
mut fullpath := calloc(MAX_PATH)
|
mut fullpath := calloc(MAX_PATH)
|
||||||
|
@ -923,9 +966,11 @@ pub fn walk_ext(path, ext string) []string {
|
||||||
if !os.is_dir(path) {
|
if !os.is_dir(path) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
mut files := os.ls(path) or { panic(err) }
|
mut files := os.ls(path)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
mut res := []string
|
mut res := []string
|
||||||
separator := if path.ends_with(path_separator) { '' } else { path_separator}
|
separator := if path.ends_with(path_separator) { '' } else { path_separator }
|
||||||
for i, file in files {
|
for i, file in files {
|
||||||
if file.starts_with('.') {
|
if file.starts_with('.') {
|
||||||
continue
|
continue
|
||||||
|
@ -947,7 +992,9 @@ pub fn walk(path string, fnc fn(path string)) {
|
||||||
if !os.is_dir(path) {
|
if !os.is_dir(path) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mut files := os.ls(path) or { panic(err) }
|
mut files := os.ls(path)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
for file in files {
|
for file in files {
|
||||||
p := path + os.path_separator + file
|
p := path + os.path_separator + file
|
||||||
if os.is_dir(p) {
|
if os.is_dir(p) {
|
||||||
|
@ -964,10 +1011,12 @@ pub fn signal(signum int, handler voidptr) {
|
||||||
C.signal(signum, handler)
|
C.signal(signum, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn C.fork() int
|
fn C.fork() int
|
||||||
|
|
||||||
|
|
||||||
fn C.wait() int
|
fn C.wait() int
|
||||||
|
|
||||||
|
|
||||||
pub fn fork() int {
|
pub fn fork() int {
|
||||||
mut pid := -1
|
mut pid := -1
|
||||||
$if !windows {
|
$if !windows {
|
||||||
|
@ -991,15 +1040,15 @@ pub fn wait() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_last_mod_unix(path string) int {
|
pub fn file_last_mod_unix(path string) int {
|
||||||
attr := C.stat{}
|
attr := C.stat{
|
||||||
//# struct stat attr;
|
}
|
||||||
|
// # struct stat attr;
|
||||||
C.stat(path.str, &attr)
|
C.stat(path.str, &attr)
|
||||||
//# stat(path.str, &attr);
|
// # stat(path.str, &attr);
|
||||||
return attr.st_mtime
|
return attr.st_mtime
|
||||||
//# return attr.st_mtime ;
|
// # return attr.st_mtime ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn log(s string) {
|
pub fn log(s string) {
|
||||||
println('os.log: ' + s)
|
println('os.log: ' + s)
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +1058,7 @@ pub fn flush_stdout() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_backtrace() {
|
pub fn print_backtrace() {
|
||||||
/*
|
/*
|
||||||
# void *buffer[100];
|
# void *buffer[100];
|
||||||
nptrs := 0
|
nptrs := 0
|
||||||
# nptrs = backtrace(buffer, 100);
|
# nptrs = backtrace(buffer, 100);
|
||||||
|
@ -1023,24 +1072,30 @@ pub fn mkdir_all(path string) {
|
||||||
for subdir in path.split(os.path_separator) {
|
for subdir in path.split(os.path_separator) {
|
||||||
p += subdir + os.path_separator
|
p += subdir + os.path_separator
|
||||||
if !os.is_dir(p) {
|
if !os.is_dir(p) {
|
||||||
os.mkdir(p) or { panic(err) }
|
os.mkdir(p)or{
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn join(base string, dirs ...string) string {
|
pub fn join(base string, dirs ...string) string {
|
||||||
println('use filepath.join')
|
println('use filepath.join')
|
||||||
return filepath.join(base, dirs)
|
return filepath.join(base,dirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tmpdir returns the path to a folder, that is suitable for storing temporary files
|
// tmpdir returns the path to a folder, that is suitable for storing temporary files
|
||||||
pub fn tmpdir() string {
|
pub fn tmpdir() string {
|
||||||
mut path := os.getenv('TMPDIR')
|
mut path := os.getenv('TMPDIR')
|
||||||
$if linux {
|
$if linux {
|
||||||
if path == '' { path = '/tmp' }
|
if path == '' {
|
||||||
|
path = '/tmp'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$if freebsd {
|
$if freebsd {
|
||||||
if path == '' { path = '/tmp' }
|
if path == '' {
|
||||||
|
path = '/tmp'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$if macos {
|
$if macos {
|
||||||
/*
|
/*
|
||||||
|
@ -1049,7 +1104,9 @@ pub fn tmpdir() string {
|
||||||
path = C.NSTemporaryDirectory()
|
path = C.NSTemporaryDirectory()
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if path == '' { path = '/tmp' }
|
if path == '' {
|
||||||
|
path = '/tmp'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
if path == '' {
|
if path == '' {
|
||||||
|
@ -1057,18 +1114,22 @@ pub fn tmpdir() string {
|
||||||
// https://doc.qt.io/qt-5/qdir.html#tempPath
|
// https://doc.qt.io/qt-5/qdir.html#tempPath
|
||||||
// https://github.com/qt/qtbase/blob/e164d61ca8263fc4b46fdd916e1ea77c7dd2b735/src/corelib/io/qfilesystemengine_win.cpp#L1275
|
// https://github.com/qt/qtbase/blob/e164d61ca8263fc4b46fdd916e1ea77c7dd2b735/src/corelib/io/qfilesystemengine_win.cpp#L1275
|
||||||
path = os.getenv('TEMP')
|
path = os.getenv('TEMP')
|
||||||
if path == '' { path = os.getenv('TMP') }
|
if path == '' {
|
||||||
if path == '' { path = 'C:/tmp' }
|
path = os.getenv('TMP')
|
||||||
|
}
|
||||||
|
if path == '' {
|
||||||
|
path = 'C:/tmp'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn chmod(path string, mode int) {
|
pub fn chmod(path string, mode int) {
|
||||||
C.chmod(path.str, mode)
|
C.chmod(path.str, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
wd_at_startup = getwd()
|
wd_at_startup = getwd()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ module os
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
path_separator = '/'
|
path_separator = '/'
|
||||||
)
|
)
|
||||||
|
@ -15,7 +14,6 @@ pub fn init_os_args(argc int, argv &byteptr) []string {
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// get_error_msg return error code representation in string.
|
// get_error_msg return error code representation in string.
|
||||||
pub fn get_error_msg(code int) string {
|
pub fn get_error_msg(code int) string {
|
||||||
ptr_text := C.strerror(code) // voidptr?
|
ptr_text := C.strerror(code) // voidptr?
|
||||||
|
@ -32,7 +30,7 @@ pub fn ls(path string) ?[]string {
|
||||||
return error('ls() couldnt open dir "$path"')
|
return error('ls() couldnt open dir "$path"')
|
||||||
}
|
}
|
||||||
mut ent := &C.dirent(0)
|
mut ent := &C.dirent(0)
|
||||||
//mut ent := &C.dirent{!}
|
// mut ent := &C.dirent{!}
|
||||||
for {
|
for {
|
||||||
ent = C.readdir(dir)
|
ent = C.readdir(dir)
|
||||||
if isnil(ent) {
|
if isnil(ent) {
|
||||||
|
@ -63,8 +61,10 @@ pub fn is_dir(path string) bool {
|
||||||
|
|
||||||
// mkdir creates a new directory with the specified path.
|
// mkdir creates a new directory with the specified path.
|
||||||
pub fn mkdir(path string) ?bool {
|
pub fn mkdir(path string) ?bool {
|
||||||
if path == '.' { return true }
|
if path == '.' {
|
||||||
apath := os.realpath( path )
|
return true
|
||||||
|
}
|
||||||
|
apath := os.realpath(path)
|
||||||
r := C.mkdir(apath.str, 511)
|
r := C.mkdir(apath.str, 511)
|
||||||
if r == -1 {
|
if r == -1 {
|
||||||
return error(get_error_msg(C.errno))
|
return error(get_error_msg(C.errno))
|
||||||
|
@ -74,9 +74,9 @@ pub fn mkdir(path string) ?bool {
|
||||||
|
|
||||||
// exec starts the specified command, waits for it to complete, and returns its output.
|
// exec starts the specified command, waits for it to complete, and returns its output.
|
||||||
pub fn exec(cmd string) ?Result {
|
pub fn exec(cmd string) ?Result {
|
||||||
//if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
|
// if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') {
|
||||||
//return error(';, &&, || and \\n are not allowed in shell commands')
|
// return error(';, &&, || and \\n are not allowed in shell commands')
|
||||||
//}
|
// }
|
||||||
pcmd := '$cmd 2>&1'
|
pcmd := '$cmd 2>&1'
|
||||||
f := vpopen(pcmd)
|
f := vpopen(pcmd)
|
||||||
if isnil(f) {
|
if isnil(f) {
|
||||||
|
@ -89,11 +89,12 @@ pub fn exec(cmd string) ?Result {
|
||||||
}
|
}
|
||||||
res = res.trim_space()
|
res = res.trim_space()
|
||||||
exit_code := vpclose(f)
|
exit_code := vpclose(f)
|
||||||
//if exit_code != 0 {
|
// if exit_code != 0 {
|
||||||
//return error(res)
|
// return error(res)
|
||||||
//}
|
// }
|
||||||
return Result {
|
return Result{
|
||||||
output: res
|
output: res
|
||||||
exit_code: exit_code
|
exit_code: exit_code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,58 @@
|
||||||
module rand
|
module rand
|
||||||
|
|
||||||
// Ported from http://www.pcg-random.org/download.html
|
// Ported from http://www.pcg-random.org/download.html
|
||||||
// and https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c
|
// and https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c
|
||||||
|
|
||||||
pub struct Pcg32 {
|
pub struct Pcg32 {
|
||||||
mut:
|
mut:
|
||||||
state u64
|
state u64
|
||||||
inc u64
|
inc u64
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new_pcg32 - a Pcg32 PRNG generator
|
* new_pcg32 - a Pcg32 PRNG generator
|
||||||
* @param initstate - the initial state of the PRNG.
|
* @param initstate - the initial state of the PRNG.
|
||||||
* @param initseq - the stream/step of the PRNG.
|
* @param initseq - the stream/step of the PRNG.
|
||||||
* @return a new Pcg32 PRNG instance
|
* @return a new Pcg32 PRNG instance
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
pub fn new_pcg32(initstate u64, initseq u64) Pcg32 {
|
pub fn new_pcg32(initstate u64, initseq u64) Pcg32 {
|
||||||
mut rng := Pcg32{}
|
mut rng := Pcg32{
|
||||||
|
}
|
||||||
rng.state = u64(0)
|
rng.state = u64(0)
|
||||||
rng.inc = (initseq << u64(1)) | u64(1)
|
rng.inc = (initseq<<u64(1)) | u64(1)
|
||||||
rng.next()
|
rng.next()
|
||||||
rng.state += initstate
|
rng.state += initstate
|
||||||
rng.next()
|
rng.next()
|
||||||
return rng
|
return rng
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pcg32.next - update the PRNG state and get back the next random number
|
* Pcg32.next - update the PRNG state and get back the next random number
|
||||||
* @return the generated pseudo random number
|
* @return the generated pseudo random number
|
||||||
*/
|
*/
|
||||||
[inline] pub fn (rng mut Pcg32) next() u32 {
|
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (rng mut Pcg32) next() u32 {
|
||||||
oldstate := rng.state
|
oldstate := rng.state
|
||||||
rng.state = oldstate * (6364136223846793005) + rng.inc
|
rng.state = oldstate * (6364136223846793005) + rng.inc
|
||||||
xorshifted := u32( ( (oldstate >> u64(18)) ^ oldstate) >> u64(27) )
|
xorshifted := u32(((oldstate>>u64(18)) ^ oldstate)>>u64(27))
|
||||||
rot := u32( oldstate >> u64(59) )
|
rot := u32(oldstate>>u64(59))
|
||||||
return ( (xorshifted >> rot) | (xorshifted << ((-rot) & u32(31))) )
|
return ((xorshifted>>rot) | (xorshifted<<((-rot) & u32(31))))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pcg32.bounded_next - update the PRNG state. Get the next number < bound
|
* Pcg32.bounded_next - update the PRNG state. Get the next number < bound
|
||||||
* @param bound - the returned random number will be < bound
|
* @param bound - the returned random number will be < bound
|
||||||
* @return the generated pseudo random number
|
* @return the generated pseudo random number
|
||||||
*/
|
*/
|
||||||
[inline] pub fn (rng mut Pcg32) bounded_next(bound u32) u32 {
|
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (rng mut Pcg32) bounded_next(bound u32) u32 {
|
||||||
// To avoid bias, we need to make the range of the RNG a multiple of
|
// To avoid bias, we need to make the range of the RNG a multiple of
|
||||||
// bound, which we do by dropping output less than a threshold.
|
// bound, which we do by dropping output less than a threshold.
|
||||||
threshold := ( -bound % bound )
|
threshold := (-bound % bound)
|
||||||
// Uniformity guarantees that loop below will terminate. In practice, it
|
// Uniformity guarantees that loop below will terminate. In practice, it
|
||||||
// should usually terminate quickly; on average (assuming all bounds are
|
// should usually terminate quickly; on average (assuming all bounds are
|
||||||
// equally likely), 82.25% of the time, we can expect it to require just
|
// equally likely), 82.25% of the time, we can expect it to require just
|
||||||
|
@ -51,8 +61,9 @@ pub fn new_pcg32(initstate u64, initseq u64) Pcg32 {
|
||||||
for {
|
for {
|
||||||
r := rng.next()
|
r := rng.next()
|
||||||
if r >= threshold {
|
if r >= threshold {
|
||||||
return ( r % bound )
|
return (r % bound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return u32(0)
|
return u32(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module rand
|
module rand
|
||||||
|
|
||||||
pub fn seed(s int) {
|
pub fn seed(s int) {
|
||||||
|
@ -13,7 +12,6 @@ pub fn next(max int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.rand() int
|
fn C.rand() int
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rand_r - reentrant pseudo-random number generator
|
* rand_r - reentrant pseudo-random number generator
|
||||||
*
|
*
|
||||||
|
@ -21,11 +19,15 @@ fn C.rand() int
|
||||||
*
|
*
|
||||||
* @return a value between 0 and C.RAND_MAX (inclusive)
|
* @return a value between 0 and C.RAND_MAX (inclusive)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn rand_r(seed &int) int {
|
pub fn rand_r(seed &int) int {
|
||||||
unsafe {
|
unsafe{
|
||||||
mut rs := seed
|
mut rs := seed
|
||||||
ns := ( *rs * 1103515245 + 12345 )
|
ns := (*rs * 1103515245 + 12345)
|
||||||
*rs = ns
|
*rs = ns
|
||||||
return ns & 0x7fffffff
|
return ns & 0x7fffffff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,46 @@
|
||||||
module rand
|
module rand
|
||||||
|
|
||||||
// Ported from http://xoshiro.di.unimi.it/splitmix64.c
|
// Ported from http://xoshiro.di.unimi.it/splitmix64.c
|
||||||
|
|
||||||
struct Splitmix64 {
|
struct Splitmix64 {
|
||||||
mut:
|
mut:
|
||||||
state u64
|
state u64
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new_splitmix64 - a Splitmix64 PRNG generator
|
* new_splitmix64 - a Splitmix64 PRNG generator
|
||||||
* @param seed the initial seed of the PRNG.
|
* @param seed the initial seed of the PRNG.
|
||||||
* @return a new Splitmix64 PRNG instance
|
* @return a new Splitmix64 PRNG instance
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
pub fn new_splitmix64(seed u64) Splitmix64 {
|
pub fn new_splitmix64(seed u64) Splitmix64 {
|
||||||
return Splitmix64{ seed }
|
return Splitmix64{
|
||||||
|
seed}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splitmix64.next - update the PRNG state and get back the next random number
|
* Splitmix64.next - update the PRNG state and get back the next random number
|
||||||
* @return the generated pseudo random number
|
* @return the generated pseudo random number
|
||||||
*/
|
*/
|
||||||
[inline] pub fn (rng mut Splitmix64) next() u64 {
|
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (rng mut Splitmix64) next() u64 {
|
||||||
rng.state += (0x9e3779b97f4a7c15)
|
rng.state += (0x9e3779b97f4a7c15)
|
||||||
mut z := rng.state
|
mut z := rng.state
|
||||||
z = (z ^ ((z >> u64(30)))) * (0xbf58476d1ce4e5b9)
|
z = (z ^ ((z>>u64(30)))) * (0xbf58476d1ce4e5b9)
|
||||||
z = (z ^ ((z >> u64(27)))) * (0x94d049bb133111eb)
|
z = (z ^ ((z>>u64(27)))) * (0x94d049bb133111eb)
|
||||||
return z ^ (z >> (31))
|
return z ^ (z>>(31))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splitmix64.bounded_next - Get the next random number < bound
|
* Splitmix64.bounded_next - Get the next random number < bound
|
||||||
* @param bound - the returned random number will be < bound
|
* @param bound - the returned random number will be < bound
|
||||||
* @return the generated pseudo random number
|
* @return the generated pseudo random number
|
||||||
*/
|
*/
|
||||||
[inline] pub fn (rng mut Splitmix64) bounded_next(bound u64) u64 {
|
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (rng mut Splitmix64) bounded_next(bound u64) u64 {
|
||||||
threshold := -bound % bound
|
threshold := -bound % bound
|
||||||
for {
|
for {
|
||||||
r := rng.next()
|
r := rng.next()
|
||||||
|
@ -40,3 +50,4 @@ pub fn new_splitmix64(seed u64) Splitmix64 {
|
||||||
}
|
}
|
||||||
return u64(0)
|
return u64(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,38 +19,38 @@
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
module strconv
|
module strconv
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
*
|
*
|
||||||
* 96 bit operation utilities
|
* 96 bit operation utilities
|
||||||
* Note: when u128 will be available these function can be refactored
|
* Note: when u128 will be available these function can be refactored
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
// right logical shift 96 bit
|
// right logical shift 96 bit
|
||||||
fn lsr96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) {
|
fn lsr96(s2 u32, s1 u32, s0 u32) (u32,u32,u32) {
|
||||||
mut r0 := u32(0)
|
mut r0 := u32(0)
|
||||||
mut r1 := u32(0)
|
mut r1 := u32(0)
|
||||||
mut r2 := u32(0)
|
mut r2 := u32(0)
|
||||||
r0 = (s0 >> 1) | ((s1 & u32(1)) << 31)
|
r0 = (s0>>1) | ((s1 & u32(1))<<31)
|
||||||
r1 = (s1 >> 1) | ((s2 & u32(1)) << 31)
|
r1 = (s1>>1) | ((s2 & u32(1))<<31)
|
||||||
r2 = s2 >> 1
|
r2 = s2>>1
|
||||||
return r2,r1,r0
|
return r2,r1,r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// left logical shift 96 bit
|
// left logical shift 96 bit
|
||||||
fn lsl96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) {
|
fn lsl96(s2 u32, s1 u32, s0 u32) (u32,u32,u32) {
|
||||||
mut r0 := u32(0)
|
mut r0 := u32(0)
|
||||||
mut r1 := u32(0)
|
mut r1 := u32(0)
|
||||||
mut r2 := u32(0)
|
mut r2 := u32(0)
|
||||||
r2 = (s2 << 1) | ((s1 & (u32(1) << 31)) >> 31)
|
r2 = (s2<<1) | ((s1 & (u32(1)<<31))>>31)
|
||||||
r1 = (s1 << 1) | ((s0 & (u32(1) << 31)) >> 31)
|
r1 = (s1<<1) | ((s0 & (u32(1)<<31))>>31)
|
||||||
r0 = s0 << 1
|
r0 = s0<<1
|
||||||
return r2,r1,r0
|
return r2,r1,r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// sum on 96 bit
|
// sum on 96 bit
|
||||||
fn add96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) {
|
fn add96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32,u32,u32) {
|
||||||
mut w := u64(0)
|
mut w := u64(0)
|
||||||
mut r0 := u32(0)
|
mut r0 := u32(0)
|
||||||
mut r1 := u32(0)
|
mut r1 := u32(0)
|
||||||
mut r2 := u32(0)
|
mut r2 := u32(0)
|
||||||
|
@ -66,8 +66,8 @@ fn add96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// subtraction on 96 bit
|
// subtraction on 96 bit
|
||||||
fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) {
|
fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32,u32,u32) {
|
||||||
mut w := u64(0)
|
mut w := u64(0)
|
||||||
mut r0 := u32(0)
|
mut r0 := u32(0)
|
||||||
mut r1 := u32(0)
|
mut r1 := u32(0)
|
||||||
mut r2 := u32(0)
|
mut r2 := u32(0)
|
||||||
|
@ -87,62 +87,58 @@ fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) {
|
||||||
* Constants
|
* Constants
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
const (
|
|
||||||
//
|
|
||||||
// f64 constants
|
|
||||||
//
|
|
||||||
DIGITS = 18
|
|
||||||
DOUBLE_PLUS_ZERO = u64(0x0000000000000000)
|
|
||||||
DOUBLE_MINUS_ZERO = 0x8000000000000000
|
|
||||||
DOUBLE_PLUS_INFINITY = 0x7FF0000000000000
|
|
||||||
DOUBLE_MINUS_INFINITY = 0xFFF0000000000000
|
|
||||||
|
|
||||||
|
|
||||||
|
const (
|
||||||
|
//
|
||||||
|
// f64 constants
|
||||||
|
//
|
||||||
|
DIGITS = 18
|
||||||
|
DOUBLE_PLUS_ZERO = u64(0x0000000000000000)
|
||||||
|
DOUBLE_MINUS_ZERO = 0x8000000000000000
|
||||||
|
DOUBLE_PLUS_INFINITY = 0x7FF0000000000000
|
||||||
|
DOUBLE_MINUS_INFINITY = 0xFFF0000000000000
|
||||||
//
|
//
|
||||||
// parser state machine states
|
// parser state machine states
|
||||||
//
|
//
|
||||||
FSM_A = 0
|
FSM_A = 0
|
||||||
FSM_B = 1
|
FSM_B = 1
|
||||||
FSM_C = 2
|
FSM_C = 2
|
||||||
FSM_D = 3
|
FSM_D = 3
|
||||||
FSM_E = 4
|
FSM_E = 4
|
||||||
FSM_F = 5
|
FSM_F = 5
|
||||||
FSM_G = 6
|
FSM_G = 6
|
||||||
FSM_H = 7
|
FSM_H = 7
|
||||||
FSM_I = 8
|
FSM_I = 8
|
||||||
FSM_STOP = 9
|
FSM_STOP = 9
|
||||||
|
|
||||||
//
|
//
|
||||||
// Possible parser return values.
|
// Possible parser return values.
|
||||||
//
|
//
|
||||||
PARSER_OK = 0 // parser finished OK
|
PARSER_OK = 0 // parser finished OK
|
||||||
PARSER_PZERO = 1 // no digits or number is smaller than +-2^-1022
|
PARSER_PZERO = 1 // no digits or number is smaller than +-2^-1022
|
||||||
PARSER_MZERO = 2 // number is negative, module smaller
|
PARSER_MZERO = 2 // number is negative, module smaller
|
||||||
PARSER_PINF = 3 // number is higher than +HUGE_VAL
|
PARSER_PINF = 3 // number is higher than +HUGE_VAL
|
||||||
PARSER_MINF = 4 // number is lower than -HUGE_VAL
|
PARSER_MINF = 4 // number is lower than -HUGE_VAL
|
||||||
|
|
||||||
//
|
//
|
||||||
// char constants
|
// char constants
|
||||||
// Note: Modify these if working with non-ASCII encoding
|
// Note: Modify these if working with non-ASCII encoding
|
||||||
//
|
//
|
||||||
DPOINT =`.`
|
DPOINT = `.`
|
||||||
PLUS =`+`
|
PLUS = `+`
|
||||||
MINUS =`-`
|
MINUS = `-`
|
||||||
ZERO =`0`
|
ZERO = `0`
|
||||||
NINE =`9`
|
NINE = `9`
|
||||||
|
TEN = u32(10)
|
||||||
TEN = u32(10)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
*
|
*
|
||||||
* Utility
|
* Utility
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
// NOTE: Modify these if working with non-ASCII encoding
|
|
||||||
|
|
||||||
|
// NOTE: Modify these if working with non-ASCII encoding
|
||||||
fn is_digit(x byte) bool {
|
fn is_digit(x byte) bool {
|
||||||
return (x >= ZERO && x <=NINE) == true
|
return (x >= ZERO && x <= NINE) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_space(x byte) bool {
|
fn is_space(x byte) bool {
|
||||||
|
@ -177,97 +173,98 @@ pub fn strlong(x f64) string {
|
||||||
* Support struct
|
* Support struct
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
// The structure is filled by parser, then given to converter.
|
// The structure is filled by parser, then given to converter.
|
||||||
pub struct PrepNumber
|
pub struct PrepNumber {
|
||||||
{
|
|
||||||
pub mut:
|
pub mut:
|
||||||
negative bool = false // 0 if positive number, 1 if negative
|
negative bool=false // 0 if positive number, 1 if negative
|
||||||
exponent int = 0 // power of 10 exponent
|
exponent int=0 // power of 10 exponent
|
||||||
mantissa u64 = u64(0) // integer mantissa
|
mantissa u64=u64(0) // integer mantissa
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
*
|
*
|
||||||
* String parser
|
* String parser
|
||||||
* NOTE: #TOFIX need one char after the last char of the number
|
* NOTE: #TOFIX need one char after the last char of the number
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
// parser return a support struct with all the parsing information for the converter
|
// parser return a support struct with all the parsing information for the converter
|
||||||
fn parser(s string ) (int,PrepNumber) {
|
fn parser(s string) (int,PrepNumber) {
|
||||||
mut state := FSM_A
|
mut state := FSM_A
|
||||||
mut digx := 0
|
mut digx := 0
|
||||||
mut c := ` ` // initial value for kicking off the state machine
|
mut c := ` ` // initial value for kicking off the state machine
|
||||||
mut result := PARSER_OK
|
mut result := PARSER_OK
|
||||||
mut expneg := false
|
mut expneg := false
|
||||||
mut expexp := 0
|
mut expexp := 0
|
||||||
mut i := 0
|
mut i := 0
|
||||||
|
mut pn := PrepNumber{
|
||||||
mut pn := PrepNumber{}
|
}
|
||||||
|
|
||||||
for state != FSM_STOP {
|
for state != FSM_STOP {
|
||||||
|
match state {
|
||||||
match state {
|
|
||||||
|
|
||||||
// skip starting spaces
|
// skip starting spaces
|
||||||
FSM_A {
|
FSM_A {
|
||||||
if is_space(c)==true {
|
if is_space(c) == true {
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
} else {
|
}
|
||||||
state = FSM_B
|
else {
|
||||||
|
state = FSM_B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for the sign or point
|
// check for the sign or point
|
||||||
FSM_B {
|
FSM_B {
|
||||||
state = FSM_C
|
state = FSM_C
|
||||||
|
|
||||||
if c == PLUS {
|
if c == PLUS {
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
} else if c == MINUS {
|
}
|
||||||
|
else if c == MINUS {
|
||||||
pn.negative = true
|
pn.negative = true
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
} else if is_digit(c) {}
|
}
|
||||||
else if c == DPOINT {}
|
else if is_digit(c) {
|
||||||
|
}
|
||||||
|
else if c == DPOINT {
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
state = FSM_STOP
|
state = FSM_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip the inital zeros
|
// skip the inital zeros
|
||||||
FSM_C {
|
FSM_C {
|
||||||
if c == ZERO { c = s[i++] }
|
if c == ZERO {
|
||||||
|
c = s[i++]
|
||||||
|
}
|
||||||
else if c == DPOINT {
|
else if c == DPOINT {
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
state = FSM_D
|
state = FSM_D
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
state = FSM_E
|
state = FSM_E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reading leading zeros in the fractional part of mantissa
|
// reading leading zeros in the fractional part of mantissa
|
||||||
FSM_D {
|
FSM_D {
|
||||||
if c == ZERO {
|
if c == ZERO {
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
if pn.exponent > -2147483647 { pn.exponent-- }
|
if pn.exponent > -2147483647 {
|
||||||
|
pn.exponent--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
state = FSM_F
|
state = FSM_F
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reading integer part of mantissa
|
// reading integer part of mantissa
|
||||||
FSM_E {
|
FSM_E {
|
||||||
if is_digit(c) {
|
if is_digit(c) {
|
||||||
if digx < DIGITS {
|
if digx < DIGITS {
|
||||||
pn.mantissa *= 10
|
pn.mantissa *= 10
|
||||||
pn.mantissa += u64( c - ZERO )
|
pn.mantissa += u64(c - ZERO)
|
||||||
digx++
|
digx++
|
||||||
}
|
}
|
||||||
else if pn.exponent < 2147483647 { pn.exponent++ }
|
else if pn.exponent < 2147483647 {
|
||||||
|
pn.exponent++
|
||||||
|
}
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
|
|
||||||
}
|
}
|
||||||
else if c == DPOINT {
|
else if c == DPOINT {
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
|
@ -277,7 +274,6 @@ fn parser(s string ) (int,PrepNumber) {
|
||||||
state = FSM_F
|
state = FSM_F
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reading fractional part of mantissa
|
// reading fractional part of mantissa
|
||||||
FSM_F {
|
FSM_F {
|
||||||
if is_digit(c) {
|
if is_digit(c) {
|
||||||
|
@ -287,7 +283,6 @@ fn parser(s string ) (int,PrepNumber) {
|
||||||
pn.exponent--
|
pn.exponent--
|
||||||
digx++
|
digx++
|
||||||
}
|
}
|
||||||
|
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
}
|
}
|
||||||
else if is_exp(c) {
|
else if is_exp(c) {
|
||||||
|
@ -298,18 +293,17 @@ fn parser(s string ) (int,PrepNumber) {
|
||||||
state = FSM_G
|
state = FSM_G
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reading sign of exponent
|
// reading sign of exponent
|
||||||
FSM_G {
|
FSM_G {
|
||||||
if c == PLUS {
|
if c == PLUS {
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
} else if c == MINUS {
|
}
|
||||||
|
else if c == MINUS {
|
||||||
expneg = true
|
expneg = true
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
}
|
}
|
||||||
state = FSM_H
|
state = FSM_H
|
||||||
}
|
}
|
||||||
|
|
||||||
// skipping leading zeros of exponent
|
// skipping leading zeros of exponent
|
||||||
FSM_H {
|
FSM_H {
|
||||||
if c == ZERO {
|
if c == ZERO {
|
||||||
|
@ -319,7 +313,6 @@ fn parser(s string ) (int,PrepNumber) {
|
||||||
state = FSM_I
|
state = FSM_I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reading exponent digits
|
// reading exponent digits
|
||||||
FSM_I {
|
FSM_I {
|
||||||
if is_digit(c) {
|
if is_digit(c) {
|
||||||
|
@ -327,144 +320,125 @@ fn parser(s string ) (int,PrepNumber) {
|
||||||
expexp *= 10
|
expexp *= 10
|
||||||
expexp += int(c - ZERO)
|
expexp += int(c - ZERO)
|
||||||
}
|
}
|
||||||
|
|
||||||
c = s[i++]
|
c = s[i++]
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
state = FSM_STOP
|
state = FSM_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
else {}
|
}}
|
||||||
}
|
// C.printf("len: %d i: %d str: %s \n",s.len,i,s[..i])
|
||||||
|
if i >= s.len {
|
||||||
//C.printf("len: %d i: %d str: %s \n",s.len,i,s[..i])
|
|
||||||
if i>=s.len {
|
|
||||||
state = FSM_STOP
|
state = FSM_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if expneg {
|
if expneg {
|
||||||
expexp = -expexp
|
expexp = -expexp
|
||||||
}
|
}
|
||||||
pn.exponent += expexp
|
pn.exponent += expexp
|
||||||
|
|
||||||
if pn.mantissa == 0 {
|
if pn.mantissa == 0 {
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
result = PARSER_MZERO
|
result = PARSER_MZERO
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = PARSER_PZERO
|
result = PARSER_PZERO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pn.exponent > 309){
|
else if (pn.exponent > 309) {
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
result = PARSER_MINF
|
result = PARSER_MINF
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = PARSER_PINF
|
result = PARSER_PINF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if pn.exponent < -328 {
|
else if pn.exponent < -328 {
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
result = PARSER_MZERO
|
result = PARSER_MZERO
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = PARSER_PZERO
|
result = PARSER_PZERO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result,pn
|
return result,pn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
*
|
*
|
||||||
* Converter to the bit form of the f64 number
|
* Converter to the bit form of the f64 number
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
// converter return a u64 with the bit image of the f64 number
|
// converter return a u64 with the bit image of the f64 number
|
||||||
fn converter(pn mut PrepNumber) u64 {
|
fn converter(pn mut PrepNumber) u64 {
|
||||||
mut binexp := 92
|
mut binexp := 92
|
||||||
|
mut s2 := u32(0) // 96-bit precision integer
|
||||||
mut s2:=u32(0) // 96-bit precision integer
|
mut s1 := u32(0)
|
||||||
mut s1:=u32(0)
|
mut s0 := u32(0)
|
||||||
mut s0:=u32(0)
|
mut q2 := u32(0) // 96-bit precision integer
|
||||||
mut q2:=u32(0) // 96-bit precision integer
|
mut q1 := u32(0)
|
||||||
mut q1:=u32(0)
|
mut q0 := u32(0)
|
||||||
mut q0:=u32(0)
|
mut r2 := u32(0) // 96-bit precision integer
|
||||||
mut r2:=u32(0) // 96-bit precision integer
|
mut r1 := u32(0)
|
||||||
mut r1:=u32(0)
|
mut r0 := u32(0)
|
||||||
mut r0:=u32(0)
|
mask28 := u32(0xF<<28)
|
||||||
|
|
||||||
mask28 := u32(0xF << 28)
|
|
||||||
|
|
||||||
mut result := u64(0)
|
mut result := u64(0)
|
||||||
|
|
||||||
// working on 3 u32 to have 96 bit precision
|
// working on 3 u32 to have 96 bit precision
|
||||||
s0 = u32(pn.mantissa & u64(0x00000000FFFFFFFF))
|
s0 = u32(pn.mantissa & u64(0x00000000FFFFFFFF))
|
||||||
s1 = u32(pn.mantissa >> 32)
|
s1 = u32(pn.mantissa>>32)
|
||||||
s2 = u32(0)
|
s2 = u32(0)
|
||||||
|
|
||||||
// so we take the decimal exponent off
|
// so we take the decimal exponent off
|
||||||
for pn.exponent > 0 {
|
for pn.exponent > 0 {
|
||||||
q2, q1, q0 = lsl96(s2, s1, s0) // q = s * 2
|
q2,q1,q0 = lsl96(s2, s1, s0) // q = s * 2
|
||||||
r2, r1, r0 = lsl96(q2, q1, q0) // r = s * 4 <=> q * 2
|
r2,r1,r0 = lsl96(q2, q1, q0) // r = s * 4 <=> q * 2
|
||||||
s2, s1, s0 = lsl96(r2, r1, r0) // s = s * 8 <=> r * 2
|
s2,s1,s0 = lsl96(r2, r1, r0) // s = s * 8 <=> r * 2
|
||||||
s2, s1, s0 = add96(s2, s1, s0, q2, q1, q0) // s = (s * 8) + (s * 2) <=> s*10
|
s2,s1,s0 = add96(s2, s1, s0, q2, q1, q0) // s = (s * 8) + (s * 2) <=> s*10
|
||||||
|
|
||||||
pn.exponent--
|
pn.exponent--
|
||||||
|
|
||||||
for (s2 & mask28) != 0 {
|
for (s2 & mask28) != 0 {
|
||||||
q2, q1, q0 = lsr96(s2, s1, s0)
|
q2,q1,q0 = lsr96(s2, s1, s0)
|
||||||
binexp++
|
binexp++
|
||||||
s2 = q2
|
s2 = q2
|
||||||
s1 = q1
|
s1 = q1
|
||||||
s0 = q0
|
s0 = q0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for pn.exponent < 0 {
|
for pn.exponent < 0 {
|
||||||
for !((s2 & (u32(1) << 31)) !=0) {
|
for !((s2 & (u32(1)<<31)) != 0) {
|
||||||
q2, q1, q0 = lsl96(s2, s1, s0)
|
q2,q1,q0 = lsl96(s2, s1, s0)
|
||||||
binexp--
|
binexp--
|
||||||
s2 = q2
|
s2 = q2
|
||||||
s1 = q1
|
s1 = q1
|
||||||
s0 = q0
|
s0 = q0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
q2 = s2 / TEN
|
q2 = s2 / TEN
|
||||||
r1 = s2 % TEN
|
r1 = s2 % TEN
|
||||||
r2 = (s1 >> 8) | (r1 << 24)
|
r2 = (s1>>8) | (r1<<24)
|
||||||
q1 = r2 / TEN
|
q1 = r2 / TEN
|
||||||
r1 = r2 % TEN
|
r1 = r2 % TEN
|
||||||
r2 = ((s1 & u32(0xFF)) << 16) | (s0 >> 16) | (r1 << 24)
|
r2 = ((s1 & u32(0xFF))<<16) | (s0>>16) | (r1<<24)
|
||||||
r0 = r2 / TEN
|
r0 = r2 / TEN
|
||||||
r1 = r2 % TEN
|
r1 = r2 % TEN
|
||||||
q1 = (q1 << 8) | ((r0 & u32(0x00FF0000)) >> 16)
|
q1 = (q1<<8) | ((r0 & u32(0x00FF0000))>>16)
|
||||||
q0 = r0 << 16
|
q0 = r0<<16
|
||||||
r2 = (s0 & u32(0xFFFF)) | (r1 << 16)
|
r2 = (s0 & u32(0xFFFF)) | (r1<<16)
|
||||||
q0 |= r2 / TEN
|
q0 |= r2 / TEN
|
||||||
s2 = q2
|
s2 = q2
|
||||||
s1 = q1
|
s1 = q1
|
||||||
s0 = q0
|
s0 = q0
|
||||||
|
|
||||||
pn.exponent++
|
pn.exponent++
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// C.printf("mantissa before normalization: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp)
|
||||||
//C.printf("mantissa before normalization: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp)
|
|
||||||
|
|
||||||
// normalization, the 28 bit in s2 must the leftest one in the variable
|
// normalization, the 28 bit in s2 must the leftest one in the variable
|
||||||
if s2 != 0 || s1 != 0|| s0 != 0 {
|
if s2 != 0 || s1 != 0 || s0 != 0 {
|
||||||
for (s2 & mask28) == 0 {
|
for (s2 & mask28) == 0 {
|
||||||
q2, q1, q0 = lsl96(s2, s1, s0)
|
q2,q1,q0 = lsl96(s2, s1, s0)
|
||||||
binexp--
|
binexp--
|
||||||
s2 = q2
|
s2 = q2
|
||||||
s1 = q1
|
s1 = q1
|
||||||
s0 = q0
|
s0 = q0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounding if needed
|
// rounding if needed
|
||||||
/*
|
/*
|
||||||
* "round half to even" algorithm
|
* "round half to even" algorithm
|
||||||
|
@ -477,7 +451,6 @@ fn converter(pn mut PrepNumber) u64 {
|
||||||
* If bit 53 is 0, round down
|
* If bit 53 is 0, round down
|
||||||
* If bit 53 is 1, round up
|
* If bit 53 is 1, round up
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* test case 1 complete
|
/* test case 1 complete
|
||||||
s2=0x1FFFFFFF
|
s2=0x1FFFFFFF
|
||||||
s1=0xFFFFFF80
|
s1=0xFFFFFF80
|
||||||
|
@ -496,52 +469,47 @@ fn converter(pn mut PrepNumber) u64 {
|
||||||
s0=0x0
|
s0=0x0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//C.printf("mantissa before rounding: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp)
|
// C.printf("mantissa before rounding: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp)
|
||||||
|
|
||||||
// s1 => 0xFFFFFFxx only F are rapresented
|
// s1 => 0xFFFFFFxx only F are rapresented
|
||||||
nbit := 7
|
nbit := 7
|
||||||
check_round_bit := u32(1) << u32(nbit)
|
check_round_bit := u32(1)<<u32(nbit)
|
||||||
check_round_mask := u32(0xFFFFFFFF) << u32(nbit)
|
check_round_mask := u32(0xFFFFFFFF)<<u32(nbit)
|
||||||
|
|
||||||
if (s1 & check_round_bit) != 0 {
|
if (s1 & check_round_bit) != 0 {
|
||||||
//C.printf("need round!! cehck mask: %08x\n", s1 & ~check_round_mask )
|
// C.printf("need round!! cehck mask: %08x\n", s1 & ~check_round_mask )
|
||||||
if (s1 & ~check_round_mask) != 0 {
|
if (s1 & ~check_round_mask) != 0 {
|
||||||
//C.printf("Add 1!\n")
|
// C.printf("Add 1!\n")
|
||||||
s2,s1,s0 = add96(s2,s1,s0, 0,check_round_bit,0)
|
s2,s1,s0 = add96(s2, s1, s0, 0, check_round_bit, 0)
|
||||||
} else {
|
}
|
||||||
//C.printf("All 0!\n")
|
else {
|
||||||
if (s1 & (check_round_bit<<u32(1) )) != 0 {
|
// C.printf("All 0!\n")
|
||||||
//C.printf("Add 1 form -1 bit control!\n")
|
if (s1 & (check_round_bit<<u32(1))) != 0 {
|
||||||
s2,s1,s0 = add96(s2,s1,s0, 0,check_round_bit,0)
|
// C.printf("Add 1 form -1 bit control!\n")
|
||||||
|
s2,s1,s0 = add96(s2, s1, s0, 0, check_round_bit, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s1 = s1 & check_round_mask
|
s1 = s1 & check_round_mask
|
||||||
s0 = u32(0)
|
s0 = u32(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// recheck normalization
|
// recheck normalization
|
||||||
if s2 & (mask28<<u32(1)) != 0 {
|
if s2 & (mask28<<u32(1)) != 0 {
|
||||||
//C.printf("Renormalize!!")
|
// C.printf("Renormalize!!")
|
||||||
q2, q1, q0 = lsr96(s2, s1, s0)
|
q2,q1,q0 = lsr96(s2, s1, s0)
|
||||||
binexp--
|
binexp--
|
||||||
s2 = q2
|
s2 = q2
|
||||||
s1 = q1
|
s1 = q1
|
||||||
s0 = q0
|
s0 = q0
|
||||||
}
|
}
|
||||||
|
// tmp := ( u64(s2 & ~mask28) << 24) | ((u64(s1) + u64(128)) >> 8)
|
||||||
//tmp := ( u64(s2 & ~mask28) << 24) | ((u64(s1) + u64(128)) >> 8)
|
// C.printf("mantissa after rounding : %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp)
|
||||||
//C.printf("mantissa after rounding : %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp)
|
// C.printf("Tmp result: %016x\n",tmp)
|
||||||
//C.printf("Tmp result: %016x\n",tmp)
|
|
||||||
|
|
||||||
// end rounding
|
// end rounding
|
||||||
|
|
||||||
// offset the binary exponent IEEE 754
|
// offset the binary exponent IEEE 754
|
||||||
binexp += 1023
|
binexp += 1023
|
||||||
|
|
||||||
if binexp > 2046 {
|
if binexp > 2046 {
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
result = DOUBLE_MINUS_INFINITY
|
result = DOUBLE_MINUS_INFINITY
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = DOUBLE_PLUS_INFINITY
|
result = DOUBLE_PLUS_INFINITY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,15 +520,13 @@ fn converter(pn mut PrepNumber) u64 {
|
||||||
}
|
}
|
||||||
else if s2 != 0 {
|
else if s2 != 0 {
|
||||||
mut q := u64(0)
|
mut q := u64(0)
|
||||||
binexs2 := u64(binexp) << 52
|
binexs2 := u64(binexp)<<52
|
||||||
|
q = (u64(s2 & ~mask28)<<24) | ((u64(s1) + u64(128))>>8) | binexs2
|
||||||
q = ( u64(s2 & ~mask28) << 24) | ((u64(s1) + u64(128)) >> 8) | binexs2
|
|
||||||
if pn.negative {
|
if pn.negative {
|
||||||
q |= (u64(1) << 63)
|
q |= (u64(1)<<63)
|
||||||
}
|
}
|
||||||
result = q
|
result = q
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,21 +535,20 @@ fn converter(pn mut PrepNumber) u64 {
|
||||||
* Public functions
|
* Public functions
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
// atof64 return a f64 from a string doing a parsing operation
|
// atof64 return a f64 from a string doing a parsing operation
|
||||||
pub fn atof64(s string) f64 {
|
pub fn atof64(s string) f64 {
|
||||||
mut pn := PrepNumber{}
|
mut pn := PrepNumber{
|
||||||
|
}
|
||||||
mut res_parsing := 0
|
mut res_parsing := 0
|
||||||
|
|
||||||
mut result := f64(0)
|
mut result := f64(0)
|
||||||
result=f64(0.0)
|
result = f64(0.0)
|
||||||
mut res_ptr := *u64(&result)
|
mut res_ptr := *u64(&result)
|
||||||
|
res_parsing,pn = parser(s + ' ') // TODO: need an extra char for now
|
||||||
res_parsing, pn = parser(s+' ') // TODO: need an extra char for now
|
// println(pn)
|
||||||
//println(pn)
|
|
||||||
|
|
||||||
match res_parsing {
|
match res_parsing {
|
||||||
PARSER_OK {
|
PARSER_OK {
|
||||||
*res_ptr = converter( mut pn)
|
*res_ptr = converter(mut pn)
|
||||||
}
|
}
|
||||||
PARSER_PZERO {
|
PARSER_PZERO {
|
||||||
*res_ptr = DOUBLE_PLUS_ZERO
|
*res_ptr = DOUBLE_PLUS_ZERO
|
||||||
|
@ -597,7 +562,8 @@ pub fn atof64(s string) f64 {
|
||||||
PARSER_MINF {
|
PARSER_MINF {
|
||||||
*res_ptr = DOUBLE_MINUS_INFINITY
|
*res_ptr = DOUBLE_MINUS_INFINITY
|
||||||
}
|
}
|
||||||
else {}
|
else {
|
||||||
}
|
}}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,18 +1,15 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
// TODO: use optionals, or some way to return default with error.
|
// TODO: use optionals, or some way to return default with error.
|
||||||
|
|
||||||
module strconv
|
module strconv
|
||||||
|
|
||||||
|
const (
|
||||||
const(
|
// int_size is the size in bits of an int or uint value.
|
||||||
// int_size is the size in bits of an int or uint value.
|
// int_size = 32 << (~u32(0) >> 63)
|
||||||
// int_size = 32 << (~u32(0) >> 63)
|
// max_u64 = u64(u64(1 << 63) - 1)
|
||||||
// max_u64 = u64(u64(1 << 63) - 1)
|
|
||||||
int_size = 32
|
int_size = 32
|
||||||
max_u64 = u64(C.UINT64_MAX) // use this until we add support
|
max_u64 = u64(C.UINT64_MAX) // use this until we add support
|
||||||
)
|
)
|
||||||
|
|
||||||
fn byte_to_lower(c byte) byte {
|
fn byte_to_lower(c byte) byte {
|
||||||
|
@ -24,17 +21,16 @@ fn byte_to_lower(c byte) byte {
|
||||||
pub fn common_parse_uint(s string, _base int, _bit_size int, error_on_non_digit bool, error_on_high_digit bool) u64 {
|
pub fn common_parse_uint(s string, _base int, _bit_size int, error_on_non_digit bool, error_on_high_digit bool) u64 {
|
||||||
mut bit_size := _bit_size
|
mut bit_size := _bit_size
|
||||||
mut base := _base
|
mut base := _base
|
||||||
|
|
||||||
if s.len < 1 || !underscore_ok(s) {
|
if s.len < 1 || !underscore_ok(s) {
|
||||||
// return error('parse_uint: syntax error $s')
|
// return error('parse_uint: syntax error $s')
|
||||||
return u64(0)
|
return u64(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
base0 := base == 0
|
base0 := base == 0
|
||||||
mut start_index := 0
|
mut start_index := 0
|
||||||
if 2 <= base && base <= 36 {
|
if 2 <= base && base <= 36 {
|
||||||
// valid base; nothing to do
|
// valid base; nothing to do
|
||||||
} else if base == 0 {
|
}
|
||||||
|
else if base == 0 {
|
||||||
// Look for octal, hex prefix.
|
// Look for octal, hex prefix.
|
||||||
base = 10
|
base = 10
|
||||||
if s[0] == `0` {
|
if s[0] == `0` {
|
||||||
|
@ -51,39 +47,34 @@ pub fn common_parse_uint(s string, _base int, _bit_size int, error_on_non_digit
|
||||||
start_index += 2
|
start_index += 2
|
||||||
}
|
}
|
||||||
// manage leading zeros in decimal base's numbers
|
// manage leading zeros in decimal base's numbers
|
||||||
else if s.len >=2 && ( s[1] >= `0` && s[1] <= `9`) {
|
else if s.len >= 2 && (s[1] >= `0` && s[1] <= `9`) {
|
||||||
base = 10
|
base = 10
|
||||||
start_index ++
|
start_index++
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
base = 8
|
base = 8
|
||||||
start_index++
|
start_index++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// return error('parse_uint: base error $s - $base')
|
// return error('parse_uint: base error $s - $base')
|
||||||
return u64(0)
|
return u64(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bit_size == 0 {
|
if bit_size == 0 {
|
||||||
bit_size = int_size
|
bit_size = int_size
|
||||||
} else if bit_size < 0 || bit_size > 64 {
|
}
|
||||||
|
else if bit_size < 0 || bit_size > 64 {
|
||||||
// return error('parse_uint: bitsize error $s - $bit_size')
|
// return error('parse_uint: bitsize error $s - $bit_size')
|
||||||
return u64(0)
|
return u64(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cutoff is the smallest number such that cutoff*base > maxUint64.
|
// Cutoff is the smallest number such that cutoff*base > maxUint64.
|
||||||
// Use compile-time constants for common cases.
|
// Use compile-time constants for common cases.
|
||||||
cutoff := max_u64/u64(base) + u64(1)
|
cutoff := max_u64 / u64(base) + u64(1)
|
||||||
max_val := if bit_size == 64 {
|
max_val := if bit_size == 64 { max_u64 } else { (u64(1)<<u64(bit_size)) - u64(1) }
|
||||||
max_u64
|
|
||||||
} else {
|
|
||||||
(u64(1)<<u64(bit_size))-u64(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
mut underscores := false
|
mut underscores := false
|
||||||
mut n := u64(0)
|
mut n := u64(0)
|
||||||
for i in start_index..s.len {
|
for i in start_index .. s.len {
|
||||||
c := s[i]
|
c := s[i]
|
||||||
cl := byte_to_lower(c)
|
cl := byte_to_lower(c)
|
||||||
mut d := byte(0)
|
mut d := byte(0)
|
||||||
|
@ -92,13 +83,18 @@ pub fn common_parse_uint(s string, _base int, _bit_size int, error_on_non_digit
|
||||||
underscores = true
|
underscores = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
else if `0` <= c && c <= `9` { d = c - `0` }
|
else if `0` <= c && c <= `9` {
|
||||||
else if `a` <= cl && cl <= `z` { d = cl - `a` + 10 }
|
d = c - `0`
|
||||||
|
}
|
||||||
|
else if `a` <= cl && cl <= `z` {
|
||||||
|
d = cl - `a` + 10
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if error_on_non_digit {
|
if error_on_non_digit {
|
||||||
// return error('parse_uint: syntax error $s')
|
// return error('parse_uint: syntax error $s')
|
||||||
return u64(0)
|
return u64(0)
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +102,8 @@ pub fn common_parse_uint(s string, _base int, _bit_size int, error_on_non_digit
|
||||||
if error_on_high_digit {
|
if error_on_high_digit {
|
||||||
// return error('parse_uint: syntax error $s')
|
// return error('parse_uint: syntax error $s')
|
||||||
return u64(0)
|
return u64(0)
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +138,6 @@ pub fn parse_uint(s string, _base int, _bit_size int) u64 {
|
||||||
pub fn common_parse_int(_s string, base int, _bit_size int, error_on_non_digit bool, error_on_high_digit bool) i64 {
|
pub fn common_parse_int(_s string, base int, _bit_size int, error_on_non_digit bool, error_on_high_digit bool) i64 {
|
||||||
mut s := _s
|
mut s := _s
|
||||||
mut bit_size := _bit_size
|
mut bit_size := _bit_size
|
||||||
|
|
||||||
if s.len < 1 {
|
if s.len < 1 {
|
||||||
// return error('parse_int: syntax error $s')
|
// return error('parse_int: syntax error $s')
|
||||||
return i64(0)
|
return i64(0)
|
||||||
|
@ -150,37 +146,35 @@ pub fn common_parse_int(_s string, base int, _bit_size int, error_on_non_digit b
|
||||||
mut neg := false
|
mut neg := false
|
||||||
if s[0] == `+` {
|
if s[0] == `+` {
|
||||||
s = s[1..]
|
s = s[1..]
|
||||||
} else if s[0] == `-` {
|
}
|
||||||
|
else if s[0] == `-` {
|
||||||
neg = true
|
neg = true
|
||||||
s = s[1..]
|
s = s[1..]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert unsigned and check range.
|
// Convert unsigned and check range.
|
||||||
// un := parse_uint(s, base, bit_size) or {
|
// un := parse_uint(s, base, bit_size) or {
|
||||||
// return i64(0)
|
// return i64(0)
|
||||||
// }
|
// }
|
||||||
un := common_parse_uint(s, base, bit_size, error_on_non_digit, error_on_high_digit)
|
un := common_parse_uint(s, base, bit_size, error_on_non_digit, error_on_high_digit)
|
||||||
if un == 0 {
|
if un == 0 {
|
||||||
return i64(0)
|
return i64(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if bit_size == 0 {
|
if bit_size == 0 {
|
||||||
bit_size = int_size
|
bit_size = int_size
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check should u64(bit_size-1) be size of int (32)?
|
// TODO: check should u64(bit_size-1) be size of int (32)?
|
||||||
cutoff := u64(1) << u64(bit_size-1)
|
cutoff := u64(1)<<u64(bit_size - 1)
|
||||||
if !neg && un >= cutoff {
|
if !neg && un >= cutoff {
|
||||||
// return error('parse_int: range error $s0')
|
// return error('parse_int: range error $s0')
|
||||||
return i64(cutoff - u64(1))
|
return i64(cutoff - u64(1))
|
||||||
}
|
}
|
||||||
if neg && un > cutoff {
|
if neg && un > cutoff {
|
||||||
// return error('parse_int: range error $s0')
|
// return error('parse_int: range error $s0')
|
||||||
return -i64(cutoff)
|
return -i64(cutoff)
|
||||||
}
|
}
|
||||||
|
|
||||||
return if neg { -i64(un) } else { i64(un) }
|
return if neg { -i64(un) } else { i64(un) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse_int interprets a string s in the given base (0, 2 to 36) and
|
// parse_int interprets a string s in the given base (0, 2 to 36) and
|
||||||
// bit size (0 to 64) and returns the corresponding value i.
|
// bit size (0 to 64) and returns the corresponding value i.
|
||||||
//
|
//
|
||||||
|
@ -199,34 +193,29 @@ pub fn parse_int(_s string, base int, _bit_size int) i64 {
|
||||||
|
|
||||||
// atoi is equivalent to parse_int(s, 10, 0), converted to type int.
|
// atoi is equivalent to parse_int(s, 10, 0), converted to type int.
|
||||||
pub fn atoi(s string) int {
|
pub fn atoi(s string) int {
|
||||||
if (int_size == 32 && (0 < s.len && s.len < 10)) ||
|
if (int_size == 32 && (0 < s.len && s.len < 10)) || (int_size == 64 && (0 < s.len && s.len < 19)) {
|
||||||
(int_size == 64 && (0 < s.len && s.len < 19)) {
|
|
||||||
// Fast path for small integers that fit int type.
|
// Fast path for small integers that fit int type.
|
||||||
mut start_idx := 0
|
mut start_idx := 0
|
||||||
if s[0] == `-` || s[0] == `+` {
|
if s[0] == `-` || s[0] == `+` {
|
||||||
start_idx++
|
start_idx++
|
||||||
if s.len-start_idx < 1 {
|
if s.len - start_idx < 1 {
|
||||||
// return 0, &NumError{fnAtoi, s0, ErrSyntax}
|
// return 0, &NumError{fnAtoi, s0, ErrSyntax}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mut n := 0
|
mut n := 0
|
||||||
for i in start_idx..s.len {
|
for i in start_idx .. s.len {
|
||||||
ch := s[i] - `0`
|
ch := s[i] - `0`
|
||||||
if ch > 9 {
|
if ch > 9 {
|
||||||
// return 0, &NumError{fnAtoi, s0, ErrSyntax}
|
// return 0, &NumError{fnAtoi, s0, ErrSyntax}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n = n*10 + int(ch)
|
n = n * 10 + int(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
return if s[0] == `-` { -n } else { n }
|
return if s[0] == `-` { -n } else { n }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slow path for invalid, big, or underscored integers.
|
// Slow path for invalid, big, or underscored integers.
|
||||||
int64 := parse_int(s, 10, 0)
|
int64 := parse_int(s, 10, 0)
|
||||||
|
|
||||||
return int(int64)
|
return int(int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,26 +230,21 @@ fn underscore_ok(s string) bool {
|
||||||
// ! for none of the above.
|
// ! for none of the above.
|
||||||
mut saw := `^`
|
mut saw := `^`
|
||||||
mut i := 0
|
mut i := 0
|
||||||
|
|
||||||
// Optional sign.
|
// Optional sign.
|
||||||
if s.len >= 1 && (s[0] == `-` || s[0] == `+`) {
|
if s.len >= 1 && (s[0] == `-` || s[0] == `+`) {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional base prefix.
|
// Optional base prefix.
|
||||||
mut hex := false
|
mut hex := false
|
||||||
if s.len-i >= 2 && s[i] == `0` &&
|
if s.len - i >= 2 && s[i] == `0` && (byte_to_lower(s[i + 1]) == `b` || byte_to_lower(s[i + 1]) == `o` || byte_to_lower(s[i + 1]) == `x`) {
|
||||||
(byte_to_lower(s[i+1]) == `b` || byte_to_lower(s[i+1]) == `o` || byte_to_lower(s[i+1]) == `x`) {
|
|
||||||
saw = `0` // base prefix counts as a digit for "underscore as digit separator"
|
saw = `0` // base prefix counts as a digit for "underscore as digit separator"
|
||||||
hex = byte_to_lower(s[i+1]) == `x`
|
hex = byte_to_lower(s[i + 1]) == `x`
|
||||||
i+=2
|
i += 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number proper.
|
// Number proper.
|
||||||
for ; i < s.len; i++ {
|
for ; i < s.len; i++ {
|
||||||
// Digits are always okay.
|
// Digits are always okay.
|
||||||
if (`0` <= s[i] && s[i] <= `9`) ||
|
if (`0` <= s[i] && s[i] <= `9`) || (hex && `a` <= byte_to_lower(s[i]) && byte_to_lower(s[i]) <= `f`) {
|
||||||
(hex && `a` <= byte_to_lower(s[i]) && byte_to_lower(s[i]) <= `f`) {
|
|
||||||
saw = `0`
|
saw = `0`
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module strings
|
module strings
|
||||||
|
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
mut:
|
mut:
|
||||||
buf []byte
|
buf []byte
|
||||||
pub mut:
|
pub mut:
|
||||||
len int
|
len int
|
||||||
initial_size int = 1
|
initial_size int=1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_builder(initial_size int) Builder {
|
pub fn new_builder(initial_size int) Builder {
|
||||||
return Builder {
|
return Builder{
|
||||||
buf: make(0, initial_size, 1)
|
buf: make(0, initial_size, 1)
|
||||||
initial_size: initial_size
|
initial_size: initial_size
|
||||||
}
|
}
|
||||||
|
@ -31,30 +30,33 @@ pub fn (b mut Builder) write_b(data byte) {
|
||||||
|
|
||||||
pub fn (b mut Builder) write(s string) {
|
pub fn (b mut Builder) write(s string) {
|
||||||
b.buf.push_many(s.str, s.len)
|
b.buf.push_many(s.str, s.len)
|
||||||
//for c in s {
|
// for c in s {
|
||||||
//b.buf << c
|
// b.buf << c
|
||||||
//}
|
// }
|
||||||
//b.buf << []byte(s) // TODO
|
// b.buf << []byte(s) // TODO
|
||||||
b.len += s.len
|
b.len += s.len
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b mut Builder) writeln(s string) {
|
pub fn (b mut Builder) writeln(s string) {
|
||||||
//for c in s {
|
// for c in s {
|
||||||
//b.buf << c
|
// b.buf << c
|
||||||
//}
|
// }
|
||||||
b.buf.push_many(s.str, s.len)
|
b.buf.push_many(s.str, s.len)
|
||||||
//b.buf << []byte(s) // TODO
|
// b.buf << []byte(s) // TODO
|
||||||
b.buf << `\n`
|
b.buf << `\n`
|
||||||
b.len += s.len + 1
|
b.len += s.len + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b mut Builder) str() string {
|
pub fn (b mut Builder) str() string {
|
||||||
b.buf << `\0`
|
b.buf << `\0`
|
||||||
return string(b.buf, b.len)
|
return string(b.buf,b.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (b mut Builder) free() {
|
pub fn (b mut Builder) free() {
|
||||||
unsafe{ free(b.buf.data) }
|
unsafe{
|
||||||
|
free(b.buf.data)
|
||||||
|
}
|
||||||
b.buf = make(0, b.initial_size, 1)
|
b.buf = make(0, b.initial_size, 1)
|
||||||
b.len = 0
|
b.len = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
module strings
|
module strings
|
||||||
|
// #-js
|
||||||
//#-js
|
|
||||||
|
|
||||||
// use levenshtein distance algorithm to calculate
|
// use levenshtein distance algorithm to calculate
|
||||||
// the distance between between two strings (lower is closer)
|
// the distance between between two strings (lower is closer)
|
||||||
pub fn levenshtein_distance(a, b string) int {
|
pub fn levenshtein_distance(a, b string) int {
|
||||||
|
@ -66,3 +64,4 @@ pub fn dice_coefficient(s1, s2 string) f32 {
|
||||||
}
|
}
|
||||||
return (2.0 * intersection_size) / (f32(a.len) + f32(b.len) - 2)
|
return (2.0 * intersection_size) / (f32(a.len) + f32(b.len) - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,6 @@ pub fn repeat(c byte, n int) string {
|
||||||
}
|
}
|
||||||
mut arr := [c].repeat(n + 1)
|
mut arr := [c].repeat(n + 1)
|
||||||
arr[n] = `\0`
|
arr[n] = `\0`
|
||||||
return string(arr, n)
|
return string(arr,n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,20 +18,12 @@ fn supports_escape_sequences(fd int) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
// ////////////////////////////////////////////
|
||||||
|
|
||||||
pub fn ok_message(s string) string {
|
pub fn ok_message(s string) string {
|
||||||
return if can_show_color_on_stdout() {
|
return if can_show_color_on_stdout() { green(s) } else { s }
|
||||||
green( s )
|
|
||||||
}else{
|
|
||||||
s
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fail_message(s string) string {
|
pub fn fail_message(s string) string {
|
||||||
return if can_show_color_on_stdout() {
|
return if can_show_color_on_stdout() { red(s) } else { s }
|
||||||
red( s )
|
|
||||||
}else{
|
|
||||||
s
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module term
|
module term
|
||||||
|
|
||||||
pub fn format(msg, open, close string) string {
|
pub fn format(msg, open, close string) string {
|
||||||
|
@ -21,19 +20,11 @@ pub fn bg_rgb(r, g, b int, msg string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hex(hex int, msg string) string {
|
pub fn hex(hex int, msg string) string {
|
||||||
return format_rgb(
|
return format_rgb(hex>>16, hex>>8 & 0xFF, hex & 0xFF, msg, '38', '39')
|
||||||
hex >> 16,
|
|
||||||
hex >> 8 & 0xFF,
|
|
||||||
hex & 0xFF,
|
|
||||||
msg, '38', '39')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bg_hex(hex int, msg string) string {
|
pub fn bg_hex(hex int, msg string) string {
|
||||||
return format_rgb(
|
return format_rgb(hex>>16, hex>>8 & 0xFF, hex & 0xFF, msg, '48', '49')
|
||||||
hex >> 16,
|
|
||||||
hex >> 8 & 0xFF,
|
|
||||||
hex & 0xFF,
|
|
||||||
msg, '48', '49')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bg_black(msg string) string {
|
pub fn bg_black(msg string) string {
|
||||||
|
@ -199,3 +190,4 @@ pub fn yellow(msg string) string {
|
||||||
pub fn bright_yellow(msg string) string {
|
pub fn bright_yellow(msg string) string {
|
||||||
return format(msg, '93', '39')
|
return format(msg, '93', '39')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module term
|
module term
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module term
|
module term
|
||||||
|
|
||||||
// Sources for ANSI Control Sequences
|
// Sources for ANSI Control Sequences
|
||||||
// https://github.com/RajeshPatkarInstitute/Panim
|
// https://github.com/RajeshPatkarInstitute/Panim
|
||||||
// https://www.gnu.org/software/screen/manual/html_node/Control-Sequences.html
|
// https://www.gnu.org/software/screen/manual/html_node/Control-Sequences.html
|
||||||
// https://en.wikipedia.org/wiki/ANSI_escape_code
|
// https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||||
|
|
||||||
// Support for Windows
|
// Support for Windows
|
||||||
// https://en.wikipedia.org/wiki/ANSI.SYS
|
// https://en.wikipedia.org/wiki/ANSI.SYS
|
||||||
// #include <windows.h>
|
// #include <windows.h>
|
||||||
// C.SetConsoleMode(ENABLE_VIRTUAL_TERMINAL_INPUT)
|
// C.SetConsoleMode(ENABLE_VIRTUAL_TERMINAL_INPUT)
|
||||||
|
|
||||||
// Setting cursor to the given position
|
// Setting cursor to the given position
|
||||||
// x is the x coordinate
|
// x is the x coordinate
|
||||||
// y is the y coordinate
|
// y is the y coordinate
|
||||||
pub fn set_cursor_position(x int,y int) {
|
pub fn set_cursor_position(x int, y int) {
|
||||||
print('\x1b[$y;$x'+'H')
|
print('\x1b[$y;$x' + 'H')
|
||||||
}
|
}
|
||||||
|
|
||||||
// n is number of cells
|
// n is number of cells
|
||||||
|
@ -26,24 +22,24 @@ pub fn set_cursor_position(x int,y int) {
|
||||||
// direction: B is down / South
|
// direction: B is down / South
|
||||||
// direction: C is forward / East
|
// direction: C is forward / East
|
||||||
// direction: D is backward / West
|
// direction: D is backward / West
|
||||||
pub fn move(n int,direction string) {
|
pub fn move(n int, direction string) {
|
||||||
print('\x1b[$n$direction')
|
print('\x1b[$n$direction')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_up(n int) {
|
pub fn cursor_up(n int) {
|
||||||
move(n,'A')
|
move(n, 'A')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_down(n int) {
|
pub fn cursor_down(n int) {
|
||||||
move(n,'B')
|
move(n, 'B')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_forward(n int) {
|
pub fn cursor_forward(n int) {
|
||||||
move(n,'C')
|
move(n, 'C')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_back(n int) {
|
pub fn cursor_back(n int) {
|
||||||
move(n,'D')
|
move(n, 'D')
|
||||||
}
|
}
|
||||||
|
|
||||||
// type: 0 -> current cursor position to end of the screen
|
// type: 0 -> current cursor position to end of the screen
|
||||||
|
@ -51,27 +47,23 @@ pub fn cursor_back(n int) {
|
||||||
// type: 2 -> clears entire screen
|
// type: 2 -> clears entire screen
|
||||||
// type: 3 -> clears entire screen and also delete scrollback buffer
|
// type: 3 -> clears entire screen and also delete scrollback buffer
|
||||||
pub fn erase_display(t string) {
|
pub fn erase_display(t string) {
|
||||||
print('\x1b[' + t + 'J')
|
print('\x1b[' + t + 'J')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_toend()
|
pub fn erase_toend() {
|
||||||
{
|
erase_display('0')
|
||||||
erase_display('0')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_tobeg()
|
pub fn erase_tobeg() {
|
||||||
{
|
erase_display('1')
|
||||||
erase_display('1')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_clear()
|
pub fn erase_clear() {
|
||||||
{
|
erase_display('2')
|
||||||
erase_display('2')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_del_clear()
|
pub fn erase_del_clear() {
|
||||||
{
|
erase_display('3')
|
||||||
erase_display('3')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type: 0 -> current cursor position to end of the line
|
// type: 0 -> current cursor position to end of the line
|
||||||
|
@ -79,32 +71,28 @@ pub fn erase_del_clear()
|
||||||
// type: 2 -> clears entire line
|
// type: 2 -> clears entire line
|
||||||
// Note: Cursor position does not change
|
// Note: Cursor position does not change
|
||||||
pub fn erase_line(t string) {
|
pub fn erase_line(t string) {
|
||||||
print('\x1b[' + t + 'K')
|
print('\x1b[' + t + 'K')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_line_toend()
|
pub fn erase_line_toend() {
|
||||||
{
|
erase_line('0')
|
||||||
erase_line('0')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_line_tobeg()
|
pub fn erase_line_tobeg() {
|
||||||
{
|
erase_line('1')
|
||||||
erase_line('1')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_line_clear()
|
pub fn erase_line_clear() {
|
||||||
{
|
erase_line('2')
|
||||||
erase_line('2')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will make cursor appear if not visible
|
// Will make cursor appear if not visible
|
||||||
pub fn show_cursor()
|
pub fn show_cursor() {
|
||||||
{
|
|
||||||
print('\x1b[?25h')
|
print('\x1b[?25h')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will make cursor invisible
|
// Will make cursor invisible
|
||||||
pub fn hide_cursor()
|
pub fn hide_cursor() {
|
||||||
{
|
|
||||||
print('\x1b[?25l')
|
print('\x1b[?25l')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
382
vlib/time/time.v
382
vlib/time/time.v
|
@ -1,49 +1,29 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module time
|
module time
|
||||||
|
|
||||||
import rand
|
import rand
|
||||||
|
|
||||||
const (
|
const (
|
||||||
days_string = 'MonTueWedThuFriSatSun'
|
days_string = 'MonTueWedThuFriSatSun'
|
||||||
|
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||||
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
months_string = 'JanFebMarAprMayJunJulAugSepOctNovDec'
|
||||||
months_string = 'JanFebMarAprMayJunJulAugSepOctNovDec'
|
// The unsigned zero year for internal calculations.
|
||||||
|
// Must be 1 mod 400, and times before it will not compute correctly,
|
||||||
// The unsigned zero year for internal calculations.
|
// but otherwise can be changed at will.
|
||||||
// Must be 1 mod 400, and times before it will not compute correctly,
|
absolute_zero_year = i64(-292277022399)
|
||||||
// but otherwise can be changed at will.
|
seconds_per_minute = 60
|
||||||
absolute_zero_year = i64(-292277022399)
|
seconds_per_hour = 60 * seconds_per_minute
|
||||||
|
seconds_per_day = 24 * seconds_per_hour
|
||||||
seconds_per_minute = 60
|
seconds_per_week = 7 * seconds_per_day
|
||||||
seconds_per_hour = 60 * seconds_per_minute
|
days_per_400_years = 365 * 400 + 97
|
||||||
seconds_per_day = 24 * seconds_per_hour
|
days_per_100_years = 365 * 100 + 24
|
||||||
seconds_per_week = 7 * seconds_per_day
|
days_per_4_years = 365 * 4 + 1
|
||||||
days_per_400_years = 365*400 + 97
|
days_before = [0, 31, 31 + 28, 31 + 28 + 31, 31 + 28 + 31 + 30, 31 + 28 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, ]
|
||||||
days_per_100_years = 365*100 + 24
|
|
||||||
days_per_4_years = 365*4 + 1
|
|
||||||
|
|
||||||
days_before = [
|
|
||||||
0,
|
|
||||||
31,
|
|
||||||
31 + 28,
|
|
||||||
31 + 28 + 31,
|
|
||||||
31 + 28 + 31 + 30,
|
|
||||||
31 + 28 + 31 + 30 + 31,
|
|
||||||
31 + 28 + 31 + 30 + 31 + 30,
|
|
||||||
31 + 28 + 31 + 30 + 31 + 30 + 31,
|
|
||||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
|
|
||||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
|
|
||||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
|
|
||||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
|
|
||||||
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
pub struct Time {
|
pub struct Time {
|
||||||
pub:
|
pub:
|
||||||
year int
|
year int
|
||||||
|
@ -56,38 +36,41 @@ pub:
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FormatTime {
|
pub enum FormatTime {
|
||||||
hhmm12
|
hhmm12
|
||||||
hhmm24
|
hhmm24
|
||||||
hhmmss12
|
hhmmss12
|
||||||
hhmmss24
|
hhmmss24
|
||||||
no_time
|
no_time
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FormatDate {
|
pub enum FormatDate {
|
||||||
ddmmyy
|
ddmmyy
|
||||||
ddmmyyyy
|
ddmmyyyy
|
||||||
mmddyy
|
mmddyy
|
||||||
mmddyyyy
|
mmddyyyy
|
||||||
mmmd
|
mmmd
|
||||||
mmmdd
|
mmmdd
|
||||||
mmmddyyyy
|
mmmddyyyy
|
||||||
no_date
|
no_date
|
||||||
yyyymmdd
|
yyyymmdd
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FormatDelimiter {
|
pub enum FormatDelimiter {
|
||||||
dot
|
dot
|
||||||
hyphen
|
hyphen
|
||||||
slash
|
slash
|
||||||
space
|
space
|
||||||
}
|
}
|
||||||
|
|
||||||
fn C.localtime(int) &C.tm
|
fn C.localtime(int) &C.tm
|
||||||
|
|
||||||
fn remove_me_when_c_bug_is_fixed() { // TODO
|
|
||||||
|
fn remove_me_when_c_bug_is_fixed() {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct C.time_t {}
|
pub struct C.time_t {
|
||||||
|
}
|
||||||
|
|
||||||
struct C.tm {
|
struct C.tm {
|
||||||
tm_year int
|
tm_year int
|
||||||
|
@ -100,6 +83,7 @@ struct C.tm {
|
||||||
|
|
||||||
fn C.time(int) C.time_t
|
fn C.time(int) C.time_t
|
||||||
|
|
||||||
|
|
||||||
pub fn now() Time {
|
pub fn now() Time {
|
||||||
t := C.time(0)
|
t := C.time(0)
|
||||||
mut now := &C.tm(0)
|
mut now := &C.tm(0)
|
||||||
|
@ -113,82 +97,81 @@ pub fn random() Time {
|
||||||
return time.unix(rand_unix)
|
return time.unix(rand_unix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Based on Go's time package.
|
// Based on Go's time package.
|
||||||
// Copyright 2009 The Go Authors.
|
// Copyright 2009 The Go Authors.
|
||||||
pub fn unix(abs int) Time {
|
pub fn unix(abs int) Time {
|
||||||
// Split into time and day.
|
// Split into time and day.
|
||||||
mut d := abs / seconds_per_day
|
mut d := abs / seconds_per_day
|
||||||
|
|
||||||
// Account for 400 year cycles.
|
// Account for 400 year cycles.
|
||||||
mut n := d / days_per_400_years
|
mut n := d / days_per_400_years
|
||||||
mut y := 400 * n
|
mut y := 400 * n
|
||||||
d -= days_per_400_years * n
|
d -= days_per_400_years * n
|
||||||
|
|
||||||
// Cut off 100-year cycles.
|
// Cut off 100-year cycles.
|
||||||
// The last cycle has one extra leap year, so on the last day
|
// The last cycle has one extra leap year, so on the last day
|
||||||
// of that year, day / days_per_100_years will be 4 instead of 3.
|
// of that year, day / days_per_100_years will be 4 instead of 3.
|
||||||
// Cut it back down to 3 by subtracting n>>2.
|
// Cut it back down to 3 by subtracting n>>2.
|
||||||
n = d / days_per_100_years
|
n = d / days_per_100_years
|
||||||
n -= n >> 2
|
n -= n>>2
|
||||||
y += 100 * n
|
y += 100 * n
|
||||||
d -= days_per_100_years * n
|
d -= days_per_100_years * n
|
||||||
|
|
||||||
// Cut off 4-year cycles.
|
// Cut off 4-year cycles.
|
||||||
// The last cycle has a missing leap year, which does not
|
// The last cycle has a missing leap year, which does not
|
||||||
// affect the computation.
|
// affect the computation.
|
||||||
n = d / days_per_4_years
|
n = d / days_per_4_years
|
||||||
y += 4 * n
|
y += 4 * n
|
||||||
d -= days_per_4_years * n
|
d -= days_per_4_years * n
|
||||||
|
|
||||||
// Cut off years within a 4-year cycle.
|
// Cut off years within a 4-year cycle.
|
||||||
// The last year is a leap year, so on the last day of that year,
|
// The last year is a leap year, so on the last day of that year,
|
||||||
// day / 365 will be 4 instead of 3. Cut it back down to 3
|
// day / 365 will be 4 instead of 3. Cut it back down to 3
|
||||||
// by subtracting n>>2.
|
// by subtracting n>>2.
|
||||||
n = d / 365
|
n = d / 365
|
||||||
n -= n >> 2
|
n -= n>>2
|
||||||
y += n
|
y += n
|
||||||
d -= 365 * n
|
d -= 365 * n
|
||||||
|
|
||||||
yday := d
|
yday := d
|
||||||
mut day := yday
|
mut day := yday
|
||||||
|
year := abs / int(3.154e+7) + 1970 // int(i64(y) + absolute_zero_year)
|
||||||
year := abs / int(3.154e+7) + 1970 //int(i64(y) + absolute_zero_year)
|
hour := (abs % seconds_per_day) / seconds_per_hour
|
||||||
hour := (abs%seconds_per_day) / seconds_per_hour
|
|
||||||
minute := (abs % seconds_per_hour) / seconds_per_minute
|
minute := (abs % seconds_per_hour) / seconds_per_minute
|
||||||
second := (abs % seconds_per_minute)
|
second := (abs % seconds_per_minute)
|
||||||
|
|
||||||
if is_leap_year(year) {
|
if is_leap_year(year) {
|
||||||
// Leap year
|
// Leap year
|
||||||
if day > 31+29-1 {
|
if day > 31 + 29 - 1 {
|
||||||
// After leap day; pretend it wasn't there.
|
// After leap day; pretend it wasn't there.
|
||||||
day--
|
day--
|
||||||
} else if day == 31+29-1 {
|
}
|
||||||
|
else if day == 31 + 29 - 1 {
|
||||||
// Leap day.
|
// Leap day.
|
||||||
day = 29
|
day = 29
|
||||||
return Time{year:year, month:2, day:day, hour:hour, minute: minute, second: second}
|
return Time{
|
||||||
|
year: year
|
||||||
|
month: 2
|
||||||
|
day: day
|
||||||
|
hour: hour
|
||||||
|
minute: minute
|
||||||
|
second: second
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate month on assumption that every month has 31 days.
|
// Estimate month on assumption that every month has 31 days.
|
||||||
// The estimate may be too low by at most one month, so adjust.
|
// The estimate may be too low by at most one month, so adjust.
|
||||||
mut month := day / 31
|
mut month := day / 31
|
||||||
mut begin := 0
|
mut begin := 0
|
||||||
end := (days_before[month+1])
|
end := (days_before[month + 1])
|
||||||
if day >= end {
|
if day >= end {
|
||||||
month++
|
month++
|
||||||
begin = end
|
begin = end
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
begin = (days_before[month])
|
begin = (days_before[month])
|
||||||
}
|
}
|
||||||
|
|
||||||
month++ // because January is 1
|
month++ // because January is 1
|
||||||
day = day - begin + 1
|
day = day - begin + 1
|
||||||
return Time{
|
return Time{
|
||||||
year:year
|
year: year
|
||||||
month: month
|
month: month
|
||||||
day:day
|
day: day
|
||||||
hour:hour
|
hour: hour
|
||||||
minute: minute
|
minute: minute
|
||||||
second: second
|
second: second
|
||||||
uni: abs
|
uni: abs
|
||||||
|
@ -196,7 +179,7 @@ pub fn unix(abs int) Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_ctime(t tm) Time {
|
pub fn convert_ctime(t tm) Time {
|
||||||
return Time {
|
return Time{
|
||||||
year: t.tm_year + 1900
|
year: t.tm_year + 1900
|
||||||
month: t.tm_mon + 1
|
month: t.tm_mon + 1
|
||||||
day: t.tm_mday
|
day: t.tm_mday
|
||||||
|
@ -208,24 +191,23 @@ pub fn convert_ctime(t tm) Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
// format_ss returns a string for t in a given format YYYY-MM-DD HH:MM:SS in
|
// format_ss returns a string for t in a given format YYYY-MM-DD HH:MM:SS in
|
||||||
// 24h notation
|
// 24h notation
|
||||||
// @param
|
// @param
|
||||||
// @return string
|
// @return string
|
||||||
// @example 1980-07-11 21:23:42
|
// @example 1980-07-11 21:23:42
|
||||||
pub fn (t Time) format_ss() string {
|
pub fn (t Time) format_ss() string {
|
||||||
return t.get_fmt_str(.hyphen, .hhmmss24, .yyyymmdd)
|
return t.get_fmt_str(.hyphen, .hhmmss24, .yyyymmdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// format_ss returns a string for t in a given format YYYY-MM-DD HH:MM in 24h
|
// format_ss returns a string for t in a given format YYYY-MM-DD HH:MM in 24h
|
||||||
// notation
|
// notation
|
||||||
// @param
|
// @param
|
||||||
// @return string
|
// @return string
|
||||||
// @example 1980-07-11 21:23
|
// @example 1980-07-11 21:23
|
||||||
pub fn (t Time) format() string {
|
pub fn (t Time) format() string {
|
||||||
return t.get_fmt_str(.hyphen, .hhmm24, .yyyymmdd)
|
return t.get_fmt_str(.hyphen, .hhmm24, .yyyymmdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn (t Time) smonth() string {
|
pub fn (t Time) smonth() string {
|
||||||
i := t.month - 1
|
i := t.month - 1
|
||||||
return months_string[i * 3..(i + 1) * 3]
|
return months_string[i * 3..(i + 1) * 3]
|
||||||
|
@ -234,7 +216,7 @@ pub fn (t Time) smonth() string {
|
||||||
// hhmm returns a string for t in the given format HH:MM in 24h notation
|
// hhmm returns a string for t in the given format HH:MM in 24h notation
|
||||||
// @example 21:04
|
// @example 21:04
|
||||||
pub fn (t Time) hhmm() string {
|
pub fn (t Time) hhmm() string {
|
||||||
return t.get_fmt_time_str(.hhmm24)
|
return t.get_fmt_time_str(.hhmm24)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -245,27 +227,27 @@ fn (t Time) hhmm_tmp() string {
|
||||||
|
|
||||||
// hhmm12 returns a string for t in the given format HH:MM in 12h notation
|
// hhmm12 returns a string for t in the given format HH:MM in 12h notation
|
||||||
pub fn (t Time) hhmm12() string {
|
pub fn (t Time) hhmm12() string {
|
||||||
return t.get_fmt_time_str(.hhmm12)
|
return t.get_fmt_time_str(.hhmm12)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hhmmss returns a string for t in the given format HH:MM:SS in 24h notation
|
// hhmmss returns a string for t in the given format HH:MM:SS in 24h notation
|
||||||
pub fn (t Time) hhmmss() string {
|
pub fn (t Time) hhmmss() string {
|
||||||
return t.get_fmt_time_str(.hhmmss24)
|
return t.get_fmt_time_str(.hhmmss24)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ymmdd returns a string for t in the given format YYYY-MM-DD
|
// ymmdd returns a string for t in the given format YYYY-MM-DD
|
||||||
pub fn (t Time) ymmdd() string {
|
pub fn (t Time) ymmdd() string {
|
||||||
return t.get_fmt_date_str(.hyphen, .yyyymmdd)
|
return t.get_fmt_date_str(.hyphen, .yyyymmdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ddmmy returns a string for t in the given format DD.MM.YYYY
|
// ddmmy returns a string for t in the given format DD.MM.YYYY
|
||||||
pub fn (t Time) ddmmy() string {
|
pub fn (t Time) ddmmy() string {
|
||||||
return t.get_fmt_date_str(.dot, .ddmmyyyy)
|
return t.get_fmt_date_str(.dot, .ddmmyyyy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// md returns a string for t in the given format MMM D
|
// md returns a string for t in the given format MMM D
|
||||||
pub fn (t Time) md() string {
|
pub fn (t Time) md() string {
|
||||||
return t.get_fmt_date_str(.space, .mmmd)
|
return t.get_fmt_date_str(.space, .mmmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (t Time) clean() string {
|
pub fn (t Time) clean() string {
|
||||||
|
@ -275,7 +257,7 @@ pub fn (t Time) clean() string {
|
||||||
// }
|
// }
|
||||||
// Today
|
// Today
|
||||||
if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day {
|
if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day {
|
||||||
return t.get_fmt_time_str(.hhmm24)
|
return t.get_fmt_time_str(.hhmm24)
|
||||||
}
|
}
|
||||||
// This week
|
// This week
|
||||||
// if time.Since(t) < 24*7*time.Hour {
|
// if time.Since(t) < 24*7*time.Hour {
|
||||||
|
@ -283,7 +265,7 @@ pub fn (t Time) clean() string {
|
||||||
// }
|
// }
|
||||||
// This year
|
// This year
|
||||||
if t.year == nowe.year {
|
if t.year == nowe.year {
|
||||||
return t.get_fmt_str(.space, .hhmm24, .mmmd)
|
return t.get_fmt_str(.space, .hhmm24, .mmmd)
|
||||||
}
|
}
|
||||||
return t.format()
|
return t.format()
|
||||||
// return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm
|
// return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm
|
||||||
|
@ -296,7 +278,7 @@ pub fn (t Time) clean12() string {
|
||||||
// }
|
// }
|
||||||
// Today
|
// Today
|
||||||
if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day {
|
if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day {
|
||||||
return t.get_fmt_time_str(.hhmm12)
|
return t.get_fmt_time_str(.hhmm12)
|
||||||
}
|
}
|
||||||
// This week
|
// This week
|
||||||
// if time.Since(t) < 24*7*time.Hour {
|
// if time.Since(t) < 24*7*time.Hour {
|
||||||
|
@ -304,12 +286,11 @@ pub fn (t Time) clean12() string {
|
||||||
// }
|
// }
|
||||||
// This year
|
// This year
|
||||||
if t.year == nowe.year {
|
if t.year == nowe.year {
|
||||||
return t.get_fmt_str(.space, .hhmm12, .mmmd)
|
return t.get_fmt_str(.space, .hhmm12, .mmmd)
|
||||||
}
|
}
|
||||||
return t.format()
|
return t.format()
|
||||||
// return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm
|
// return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm
|
||||||
}
|
}
|
||||||
|
|
||||||
// `parse` parses time in the following format: "2018-01-27 12:48:34"
|
// `parse` parses time in the following format: "2018-01-27 12:48:34"
|
||||||
pub fn parse(s string) Time {
|
pub fn parse(s string) Time {
|
||||||
// println('parse="$s"')
|
// println('parse="$s"')
|
||||||
|
@ -329,7 +310,7 @@ pub fn parse(s string) Time {
|
||||||
minute := hms[1]
|
minute := hms[1]
|
||||||
second := hms[2]
|
second := hms[2]
|
||||||
// //////////
|
// //////////
|
||||||
return new_time(Time {
|
return new_time(Time{
|
||||||
year: ymd[0].int()
|
year: ymd[0].int()
|
||||||
month: ymd[1].int()
|
month: ymd[1].int()
|
||||||
day: ymd[2].int()
|
day: ymd[2].int()
|
||||||
|
@ -340,20 +321,23 @@ pub fn parse(s string) Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_time(t Time) Time {
|
pub fn new_time(t Time) Time {
|
||||||
return{t | uni: t.calc_unix()}
|
return {
|
||||||
|
t |
|
||||||
|
uni:t.calc_unix()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (t &Time) calc_unix() int {
|
pub fn (t &Time) calc_unix() int {
|
||||||
if t.uni != 0 {
|
if t.uni != 0 {
|
||||||
return t.uni
|
return t.uni
|
||||||
}
|
}
|
||||||
tt := C.tm{
|
tt := C.tm{
|
||||||
tm_sec : t.second
|
tm_sec: t.second
|
||||||
tm_min : t.minute
|
tm_min: t.minute
|
||||||
tm_hour : t.hour
|
tm_hour: t.hour
|
||||||
tm_mday : t.day
|
tm_mday: t.day
|
||||||
tm_mon : t.month-1
|
tm_mon: t.month - 1
|
||||||
tm_year : t.year - 1900
|
tm_year: t.year - 1900
|
||||||
}
|
}
|
||||||
return C.mktime(&tt)
|
return C.mktime(&tt)
|
||||||
}
|
}
|
||||||
|
@ -406,7 +390,7 @@ pub fn day_of_week(y, m, d int) int {
|
||||||
if (m < 3) {
|
if (m < 3) {
|
||||||
sy = sy - 1
|
sy = sy - 1
|
||||||
}
|
}
|
||||||
return ( sy + sy/4 - sy/100 + sy/400 + t[m-1] + d - 1) % 7 + 1
|
return (sy + sy / 4 - sy / 100 + sy / 400 + t[m - 1] + d - 1) % 7 + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (t Time) day_of_week() int {
|
pub fn (t Time) day_of_week() int {
|
||||||
|
@ -419,8 +403,8 @@ pub fn (t Time) weekday_str() string {
|
||||||
return days_string[i * 3..(i + 1) * 3]
|
return days_string[i * 3..(i + 1) * 3]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct C.timeval {
|
pub struct C.timeval {
|
||||||
tv_sec u64
|
tv_sec u64
|
||||||
tv_usec u64
|
tv_usec u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,50 +412,47 @@ pub struct C.timeval {
|
||||||
pub fn ticks() i64 {
|
pub fn ticks() i64 {
|
||||||
$if windows {
|
$if windows {
|
||||||
return C.GetTickCount()
|
return C.GetTickCount()
|
||||||
}
|
} $else {
|
||||||
$else {
|
ts := C.timeval{
|
||||||
ts := C.timeval{}
|
}
|
||||||
C.gettimeofday(&ts,0)
|
C.gettimeofday(&ts, 0)
|
||||||
return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1000)))
|
return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1000)))
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
/*
|
|
||||||
t := i64(C.mach_absolute_time())
|
t := i64(C.mach_absolute_time())
|
||||||
# Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t );
|
# Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t );
|
||||||
# return (double)(* (uint64_t *) &elapsedNano) / 1000000;
|
# return (double)(* (uint64_t *) &elapsedNano) / 1000000;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sleep(seconds int) {
|
pub fn sleep(seconds int) {
|
||||||
$if windows {
|
$if windows {
|
||||||
C.Sleep(seconds * 1000)
|
C.Sleep(seconds * 1000)
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
C.sleep(seconds)
|
C.sleep(seconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn usleep(n int) {
|
pub fn usleep(n int) {
|
||||||
$if windows {
|
$if windows {
|
||||||
//C._usleep(n)
|
// C._usleep(n)
|
||||||
}
|
} $else {
|
||||||
$else {
|
C.usleep(n)
|
||||||
C.usleep(n)
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sleep_ms(n int) {
|
pub fn sleep_ms(n int) {
|
||||||
$if windows {
|
$if windows {
|
||||||
C.Sleep(n)
|
C.Sleep(n)
|
||||||
}
|
} $else {
|
||||||
$else {
|
|
||||||
C.usleep(n * 1000)
|
C.usleep(n * 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine whether a year is a leap year.
|
// Determine whether a year is a leap year.
|
||||||
pub fn is_leap_year(year int) bool {
|
pub fn is_leap_year(year int) bool {
|
||||||
return (year%4 == 0) && (year%100 != 0 || year%400 == 0)
|
return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns number of days in month
|
// Returns number of days in month
|
||||||
|
@ -479,8 +460,8 @@ pub fn days_in_month(month, year int) ?int {
|
||||||
if month > 12 || month < 1 {
|
if month > 12 || month < 1 {
|
||||||
return error('Invalid month: $month')
|
return error('Invalid month: $month')
|
||||||
}
|
}
|
||||||
extra := if month == 2 && is_leap_year(year) {1} else {0}
|
extra := if month == 2 && is_leap_year(year) { 1 } else { 0 }
|
||||||
res := month_days[month-1] + extra
|
res := month_days[month - 1] + extra
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,31 +470,26 @@ pub fn days_in_month(month, year int) ?int {
|
||||||
// @return string
|
// @return string
|
||||||
// @example 21:23:42
|
// @example 21:23:42
|
||||||
pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string {
|
pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string {
|
||||||
if fmt_time == .no_time {
|
if fmt_time == .no_time {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
tp := if t.hour > 11 { 'p.m.' } else { 'a.m.' }
|
||||||
tp := if t.hour > 11 {
|
hour := if t.hour > 12 { t.hour - 12 } else if t.hour == 0 { 12 } else { t.hour }
|
||||||
'p.m.'
|
return match fmt_time {
|
||||||
} else {
|
.hhmm12{
|
||||||
'a.m.'
|
'$hour:${t.minute:02d} $tp'
|
||||||
}
|
}
|
||||||
|
.hhmm24{
|
||||||
hour := if t.hour > 12 {
|
'${t.hour:02d}:${t.minute:02d}'
|
||||||
t.hour - 12
|
}
|
||||||
} else if t.hour == 0 {
|
.hhmmss12{
|
||||||
12
|
'$hour:${t.minute:02d}:${t.second:02d} $tp'
|
||||||
} else {
|
}
|
||||||
t.hour
|
.hhmmss24{
|
||||||
}
|
'${t.hour:02d}:${t.minute:02d}:${t.second:02d}'
|
||||||
|
}
|
||||||
return match fmt_time {
|
else {
|
||||||
.hhmm12 { '$hour:${t.minute:02d} $tp' }
|
'unknown enumeration $fmt_time'}}
|
||||||
.hhmm24 { '${t.hour:02d}:${t.minute:02d}' }
|
|
||||||
.hhmmss12 { '$hour:${t.minute:02d}:${t.second:02d} $tp' }
|
|
||||||
.hhmmss24 { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}' }
|
|
||||||
else { 'unknown enumeration $fmt_time' }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_fmt_date_str returns a string for t in a given date format
|
// get_fmt_date_str returns a string for t in a given date format
|
||||||
|
@ -521,30 +497,52 @@ pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string {
|
||||||
// @return string
|
// @return string
|
||||||
// @example 11.07.1980
|
// @example 11.07.1980
|
||||||
pub fn (t Time) get_fmt_date_str(fmt_dlmtr FormatDelimiter, fmt_date FormatDate) string {
|
pub fn (t Time) get_fmt_date_str(fmt_dlmtr FormatDelimiter, fmt_date FormatDate) string {
|
||||||
if fmt_date == .no_date {
|
if fmt_date == .no_date {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
month := '${t.smonth()}'
|
||||||
month := '${t.smonth()}'
|
year := t.year.str()[2..]
|
||||||
year := t.year.str()[2..]
|
return match fmt_date {
|
||||||
|
.ddmmyy{
|
||||||
return match fmt_date {
|
'${t.day:02d}|${t.month:02d}|$year'
|
||||||
.ddmmyy { '${t.day:02d}|${t.month:02d}|$year' }
|
}
|
||||||
.ddmmyyyy { '${t.day:02d}|${t.month:02d}|${t.year}' }
|
.ddmmyyyy{
|
||||||
.mmddyy { '${t.month:02d}|${t.day:02d}|$year' }
|
'${t.day:02d}|${t.month:02d}|${t.year}'
|
||||||
.mmddyyyy { '${t.month:02d}|${t.day:02d}|${t.year}' }
|
}
|
||||||
.mmmd { '$month|${t.day}' }
|
.mmddyy{
|
||||||
.mmmdd { '$month|${t.day:02d}' }
|
'${t.month:02d}|${t.day:02d}|$year'
|
||||||
.mmmddyyyy { '$month|${t.day:02d}|${t.year}' }
|
}
|
||||||
.yyyymmdd { '${t.year}|${t.month:02d}|${t.day:02d}' }
|
.mmddyyyy{
|
||||||
else { 'unknown enumeration $fmt_date' }
|
'${t.month:02d}|${t.day:02d}|${t.year}'
|
||||||
}.replace('|', match fmt_dlmtr {
|
}
|
||||||
.dot { '.' }
|
.mmmd{
|
||||||
.hyphen { '-' }
|
'$month|${t.day}'
|
||||||
.slash { '/' }
|
}
|
||||||
.space { ' ' }
|
.mmmdd{
|
||||||
else { 'unknown enumeration $fmt_dlmtr' }
|
'$month|${t.day:02d}'
|
||||||
})
|
}
|
||||||
|
.mmmddyyyy{
|
||||||
|
'$month|${t.day:02d}|${t.year}'
|
||||||
|
}
|
||||||
|
.yyyymmdd{
|
||||||
|
'${t.year}|${t.month:02d}|${t.day:02d}'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
'unknown enumeration $fmt_date'}}.replace('|', match fmt_dlmtr {
|
||||||
|
.dot{
|
||||||
|
'.'
|
||||||
|
}
|
||||||
|
.hyphen{
|
||||||
|
'-'
|
||||||
|
}
|
||||||
|
.slash{
|
||||||
|
'/'
|
||||||
|
}
|
||||||
|
.space{
|
||||||
|
' '
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
'unknown enumeration $fmt_dlmtr'}})
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_fmt_str returns a string for t in a given format for time and date
|
// get_fmt_str returns a string for t in a given format for time and date
|
||||||
|
@ -552,21 +550,23 @@ pub fn (t Time) get_fmt_date_str(fmt_dlmtr FormatDelimiter, fmt_date FormatDate)
|
||||||
// @return string
|
// @return string
|
||||||
// @example 11.07.1980 21:23:42
|
// @example 11.07.1980 21:23:42
|
||||||
pub fn (t Time) get_fmt_str(fmt_dlmtr FormatDelimiter, fmt_time FormatTime, fmt_date FormatDate) string {
|
pub fn (t Time) get_fmt_str(fmt_dlmtr FormatDelimiter, fmt_time FormatTime, fmt_date FormatDate) string {
|
||||||
if fmt_date == .no_date {
|
if fmt_date == .no_date {
|
||||||
if fmt_time == .no_time {
|
if fmt_time == .no_time {
|
||||||
// saving one function call although it's checked in
|
// saving one function call although it's checked in
|
||||||
// t.get_fmt_time_str(fmt_time) in the beginning
|
// t.get_fmt_time_str(fmt_time) in the beginning
|
||||||
return ''
|
return ''
|
||||||
} else {
|
}
|
||||||
return t.get_fmt_time_str(fmt_time)
|
else {
|
||||||
}
|
return t.get_fmt_time_str(fmt_time)
|
||||||
} else {
|
}
|
||||||
if fmt_time != .no_time {
|
}
|
||||||
return t.get_fmt_date_str(fmt_dlmtr, fmt_date)
|
else {
|
||||||
+ ' '
|
if fmt_time != .no_time {
|
||||||
+ t.get_fmt_time_str(fmt_time)
|
return t.get_fmt_date_str(fmt_dlmtr, fmt_date) + ' ' + t.get_fmt_time_str(fmt_time)
|
||||||
} else {
|
}
|
||||||
return t.get_fmt_date_str(fmt_dlmtr, fmt_date)
|
else {
|
||||||
}
|
return t.get_fmt_date_str(fmt_dlmtr, fmt_date)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,54 +1,54 @@
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
module tmpl
|
module tmpl
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
const (
|
const (
|
||||||
STR_START = 'sb.write(\''
|
STR_START = "sb.write(\'"
|
||||||
STR_END = '\' ) '
|
STR_END = "\' ) "
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
pub fn compile_template(path string) string {
|
pub fn compile_template(path string) string {
|
||||||
//lines := os.read_lines(path)
|
// lines := os.read_lines(path)
|
||||||
mut html := os.read_file(path) or {
|
mut html := os.read_file(path)or{
|
||||||
panic('html failed')
|
panic('html failed')
|
||||||
}
|
}
|
||||||
mut header := ''
|
mut header := ''
|
||||||
if os.exists('header.html') {
|
if os.exists('header.html') {
|
||||||
h := os.read_file('header.html') or {
|
h := os.read_file('header.html')or{
|
||||||
panic('html failed')
|
panic('html failed')
|
||||||
}
|
}
|
||||||
header = h.replace('\'', '"')
|
header = h.replace("\'", '"')
|
||||||
html = header + html
|
html = header + html
|
||||||
}
|
}
|
||||||
lines := html.split_into_lines()
|
lines := html.split_into_lines()
|
||||||
mut s := strings.new_builder(1000)
|
mut s := strings.new_builder(1000)
|
||||||
//base := path.all_after('/').replace('.html', '')
|
// base := path.all_after('/').replace('.html', '')
|
||||||
s.writeln('
|
s.writeln("
|
||||||
mut sb := strings.new_builder(${lines.len * 30})
|
mut sb := strings.new_builder(${lines.len * 30})
|
||||||
header := \' \' // TODO remove
|
header := \' \' // TODO remove
|
||||||
_ = header
|
_ = header
|
||||||
//footer := \'footer\'
|
//footer := \'footer\'
|
||||||
')
|
")
|
||||||
s.writeln(STR_START)
|
s.writeln(STR_START)
|
||||||
mut in_css :=true// false
|
mut in_css := true // false
|
||||||
for _line in lines {
|
for _line in lines {
|
||||||
line := _line.trim_space()
|
line := _line.trim_space()
|
||||||
if line == '<style>' {
|
if line == '<style>' {
|
||||||
in_css = true
|
in_css = true
|
||||||
}
|
}
|
||||||
else if line == '</style>' {
|
else if line == '</style>' {
|
||||||
//in_css = false
|
// in_css = false
|
||||||
}
|
}
|
||||||
if line.contains('@if ') {
|
if line.contains('@if ') {
|
||||||
s.writeln(STR_END)
|
s.writeln(STR_END)
|
||||||
pos := line.index('@if') or { continue }
|
pos := line.index('@if') or {
|
||||||
s.writeln('if ' + line[pos+4..] + '{')
|
continue
|
||||||
|
}
|
||||||
|
s.writeln('if ' + line[pos + 4..] + '{')
|
||||||
s.writeln(STR_START)
|
s.writeln(STR_START)
|
||||||
}
|
}
|
||||||
else if line.contains('@end') {
|
else if line.contains('@end') {
|
||||||
|
@ -63,8 +63,10 @@ _ = header
|
||||||
}
|
}
|
||||||
else if line.contains('@for') {
|
else if line.contains('@for') {
|
||||||
s.writeln(STR_END)
|
s.writeln(STR_END)
|
||||||
pos := line.index('@for') or { continue }
|
pos := line.index('@for') or {
|
||||||
s.writeln('for ' + line[pos+4..] + '{')
|
continue
|
||||||
|
}
|
||||||
|
s.writeln('for ' + line[pos + 4..] + '{')
|
||||||
s.writeln(STR_START)
|
s.writeln(STR_START)
|
||||||
}
|
}
|
||||||
else if !in_css && line.contains('.') && line.ends_with('{') {
|
else if !in_css && line.contains('.') && line.ends_with('{') {
|
||||||
|
@ -76,7 +78,7 @@ _ = header
|
||||||
}
|
}
|
||||||
// HTML, may include `@var`
|
// HTML, may include `@var`
|
||||||
else {
|
else {
|
||||||
s.writeln(line.replace('@', '\x24').replace("'", '"') )
|
s.writeln(line.replace('@', '\x24').replace("'", '"'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.writeln(STR_END)
|
s.writeln(STR_END)
|
||||||
|
|
Loading…
Reference in New Issue