fmt: lots of fixes

pull/4586/head
Enzo Baldisserri 2020-04-25 17:49:16 +02:00 committed by GitHub
parent 7c080c5d4a
commit fb54a2635c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 698 additions and 550 deletions

View File

@ -8,9 +8,9 @@ import v.table
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | CharLiteral | FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | AssignExpr | PrefixExpr | IndexExpr | RangeExpr | MatchExpr | CastExpr | EnumVal | Assoc | SizeOf | None | MapInit | IfGuardExpr | ParExpr | OrExpr | ConcatExpr | Type | AsCast | TypeOf | StringInterLiteral | AnonFn
pub type Expr = AnonFn | ArrayInit | AsCast | AssignExpr | Assoc | BoolLiteral | CastExpr | CallExpr | CharLiteral | ConcatExpr | EnumVal | FloatLiteral | IfExpr | Ident | IfGuardExpr | InfixExpr | IndexExpr | IntegerLiteral | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | StringLiteral | StringInterLiteral | StructInit | Type | TypeOf
pub type Stmt = GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr | BranchStmt | HashStmt | AssignStmt | EnumDecl | TypeDecl | DeferStmt | GotoLabel | GotoStmt | Comment | AssertStmt | UnsafeStmt | GoStmt | Block | InterfaceDecl
pub type Stmt = AssignStmt | AssertStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | StructDecl | TypeDecl | UnsafeStmt
pub type ScopeObject = ConstField | GlobalDecl | Var

View File

@ -30,7 +30,7 @@ pub fn (node &FnDecl) str(t &table.Table) string {
receiver = '($node.receiver.name $m$name) '
*/
}
mut name := node.name.after('.')
mut name := if node.is_anon { '' } else { node.name.after('.') }
if node.is_c {
name = 'C.$name'
}

View File

@ -46,7 +46,7 @@ pub fn new_builder(pref &pref.Preferences) Builder {
}
// parse all deps from already parsed files
pub fn (b mut Builder) parse_imports() {
pub fn (mut b Builder) parse_imports() {
mut done_imports := []string
// NB: b.parsed_files is appended in the loop,
// so we can not use the shorter `for in` form.
@ -84,7 +84,7 @@ pub fn (b mut Builder) parse_imports() {
b.resolve_deps()
}
pub fn (b mut Builder) resolve_deps() {
pub fn (mut b Builder) resolve_deps() {
graph := b.import_graph()
deps_resolved := graph.resolve()
if !deps_resolved.acyclic {

View File

@ -1,14 +1,12 @@
module builder
import (
time
os
v.parser
v.pref
v.gen
)
import time
import os
import v.parser
import v.pref
import v.gen
pub fn (b mut Builder) gen_c(v_files []string) string {
pub fn (mut b Builder) gen_c(v_files []string) string {
t0 := time.ticks()
b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
b.parse_imports()
@ -35,7 +33,7 @@ pub fn (b mut Builder) gen_c(v_files []string) string {
return res
}
pub fn (b mut Builder) build_c(v_files []string, out_file string) {
pub fn (mut b Builder) build_c(v_files []string, out_file string) {
b.out_name_c = out_file
b.info('build_c($out_file)')
mut f := os.create(out_file) or {
@ -46,7 +44,7 @@ pub fn (b mut Builder) build_c(v_files []string, out_file string) {
// os.write_file(out_file, b.gen_c(v_files))
}
pub fn (b mut Builder) compile_c() {
pub fn (mut b Builder) compile_c() {
if os.user_os() != 'windows' && b.pref.ccompiler == 'msvc' {
verror('Cannot build with msvc on ${os.user_os()}')
}

View File

@ -3,14 +3,12 @@
// that can be found in the LICENSE file.
module builder
import (
os
time
v.cflag
v.pref
v.util
term
)
import os
import time
import v.cflag
import v.pref
import v.util
import term
fn todo() {
}
@ -27,7 +25,7 @@ fn (v &Builder) no_cc_installed() bool {
return false
}
fn (v mut Builder) cc() {
fn (mut v Builder) cc() {
if os.executable().contains('vfmt') {
return
}
@ -55,8 +53,7 @@ fn (v mut Builder) cc() {
ret := os.system('$vexe -o $vjs_path -os js $vdir/cmd/v')
if ret == 0 {
println('Done.')
}
else {
} else {
println('Failed.')
exit(1)
}
@ -95,7 +92,9 @@ fn (v mut Builder) cc() {
// warnings are totally fixed/removed
'-Wno-unused-variable',
// '-Wno-unused-but-set-variable',
'-Wno-unused-parameter', '-Wno-unused-result', '-Wno-unused-function', '-Wno-missing-braces', '-Wno-unused-label']
'-Wno-unused-parameter', '-Wno-unused-result', '-Wno-unused-function', '-Wno-missing-braces',
'-Wno-unused-label'
]
// TCC on Linux by default, unless -cc was provided
// TODO if -cc = cc, TCC is still used, default compiler should be
// used instead.
@ -125,15 +124,10 @@ fn (v mut Builder) cc() {
verror('-fast is only supported on Linux right now')
}
}
if !v.pref.is_shared
&& v.pref.build_mode != .build_module
&& os.user_os() == 'windows'
&& !v.pref.out_name.ends_with('.exe')
{
if !v.pref.is_shared && v.pref.build_mode != .build_module && os.user_os() == 'windows' &&
!v.pref.out_name.ends_with('.exe') {
v.pref.out_name += '.exe'
}
// linux_host := os.user_os() == 'linux'
v.log('cc() isprod=$v.pref.is_prod outname=$v.pref.out_name')
if v.pref.is_shared {
@ -221,8 +215,7 @@ fn (v mut Builder) cc() {
mut libs := '' // builtin.o os.o http.o etc
if v.pref.build_mode == .build_module {
a << '-c'
}
else if v.pref.is_cache {
} else if v.pref.is_cache {
/*
QTODO
builtin_o_path := os.join_path(pref.default_module_path, 'cache', 'vlib', 'builtin.o')
@ -268,7 +261,6 @@ fn (v mut Builder) cc() {
}
*/
}
if v.pref.sanitize {
a << '-fsanitize=leak'
}
@ -289,7 +281,7 @@ fn (v mut Builder) cc() {
// Output executable name
a << '-o "$v.pref.out_name"'
if os.is_dir(v.pref.out_name) {
verror("\'$v.pref.out_name\' is a directory")
verror("'$v.pref.out_name' is a directory")
}
// macOS code can include objective C TODO remove once objective C is replaced with C
if v.pref.os == .mac {
@ -313,7 +305,6 @@ fn (v mut Builder) cc() {
// add all flags (-I -l -L etc) not .o files
a << cflags.c_options_without_object_files()
a << libs
if v.pref.is_cache {
cached_files := [ 'builtin.o', 'math.o']
for cfile in cached_files {
@ -328,10 +319,10 @@ fn (v mut Builder) cc() {
}
}
}
// Without these libs compilation will fail on Linux
// || os.user_os() == 'linux'
if !v.pref.is_bare && v.pref.build_mode != .build_module && v.pref.os in [.linux, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
if !v.pref.is_bare && v.pref.build_mode != .build_module && v.pref.os in [ .linux, .freebsd,
.openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
a << '-lm -lpthread '
// -ldl is a Linux only thing. BSDs have it in libc.
if v.pref.os == .linux {
@ -367,7 +358,6 @@ start:
return
}
*/
verror(err)
return
}
@ -381,7 +371,9 @@ start:
goto start
}
}
verror('C compiler error, while attempting to run: \n' + '-----------------------------------------------------------\n' + '$cmd\n' + '-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' + 'Please reinstall it, or make it available in your PATH.\n\n' + missing_compiler_info())
verror('C compiler error, while attempting to run: \n' + '-----------------------------------------------------------\n' +
'$cmd\n' + '-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' +
'Please reinstall it, or make it available in your PATH.\n\n' + missing_compiler_info())
}
if v.pref.is_debug {
eword := 'error:'
@ -399,8 +391,7 @@ If you were not working with C interop and are not sure about what's happening,
please put the whole output in a pastebin and contact us through the following ways with a link to the pastebin:
- Raise an issue on GitHub: https://github.com/vlang/v/issues/new/choose
- Ask a question in #help on Discord: https://discord.gg/vlang")
}
else {
} else {
if res.output.len < 30 {
println(res.output)
} else {
@ -451,7 +442,6 @@ If you're confident that all of the above is true, please try running V with the
println('linux cross compilation done. resulting binary: "$v.out_name"')
}
*/
if !v.pref.is_keep_c && v.out_name_c != 'v.c' {
os.rm(v.out_name_c)
}
@ -486,7 +476,7 @@ If you're confident that all of the above is true, please try running V with the
}
}
fn (c mut Builder) cc_windows_cross() {
fn (mut c Builder) cc_windows_cross() {
/*
QTODO
println('Cross compiling for Windows...')
@ -568,8 +558,7 @@ fn (c &Builder) build_thirdparty_obj_files() {
rest_of_module_flags := c.get_rest_of_module_cflags(flag)
if c.pref.ccompiler == 'msvc' || c.no_cc_installed() {
build_thirdparty_obj_file_with_msvc(flag.value, rest_of_module_flags)
}
else {
} else {
c.build_thirdparty_obj_file(flag.value, rest_of_module_flags)
}
}

View File

@ -36,4 +36,3 @@ fn (v &Builder) get_rest_of_module_cflags(c &cflag.CFlag) []cflag.CFlag {
}
return flags
}

View File

@ -3,13 +3,11 @@
// that can be found in the LICENSE file.
module builder
import (
benchmark
os
v.pref
v.util
strings
)
import benchmark
import os
import v.pref
import v.util
import strings
fn get_vtmp_folder() string {
vtmp := os.join_path(os.temp_dir(), 'v')
@ -35,9 +33,15 @@ pub fn compile(command string, pref &pref.Preferences) {
}
mut tmark := benchmark.new_benchmark()
match pref.backend {
.c { b.compile_c() }
.js { b.compile_js() }
.x64 { b.compile_x64() }
.c {
b.compile_c()
}
.js {
b.compile_js()
}
.x64 {
b.compile_x64()
}
else {
eprintln('backend not implemented `$pref.backend`')
exit(1)
@ -53,7 +57,7 @@ pub fn compile(command string, pref &pref.Preferences) {
// v.finalize_compilation()
}
fn (b mut Builder) run_compiled_executable_and_exit() {
fn (mut b Builder) run_compiled_executable_and_exit() {
if b.pref.is_verbose {
println('============ running $b.pref.out_name ============')
}
@ -88,7 +92,7 @@ fn (b mut Builder) run_compiled_executable_and_exit() {
// 'strings' => 'VROOT/vlib/strings'
// 'installed_mod' => '~/.vmodules/installed_mod'
// 'local_mod' => '/path/to/current/dir/local_mod'
fn (v mut Builder) set_module_lookup_paths() {
fn (mut v Builder) set_module_lookup_paths() {
// Module search order:
// 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

View File

@ -1,15 +1,13 @@
module builder
import (
time
os
v.parser
v.pref
v.gen
v.gen.js
)
import time
import os
import v.parser
import v.pref
import v.gen
import v.gen.js
pub fn (b mut Builder) gen_js(v_files []string) string {
pub fn (mut b Builder) gen_js(v_files []string) string {
t0 := time.ticks()
b.parsed_files = parser.parse_files(v_files, b.table, b.pref, b.global_scope)
b.parse_imports()
@ -30,7 +28,7 @@ pub fn (b mut Builder) gen_js(v_files []string) string {
return res
}
pub fn (b mut Builder) build_js(v_files []string, out_file string) {
pub fn (mut b Builder) build_js(v_files []string, out_file string) {
b.out_name_js = out_file
b.info('build_js($out_file)')
mut f := os.create(out_file) or {
@ -40,7 +38,7 @@ pub fn (b mut Builder) build_js(v_files []string, out_file string) {
f.close()
}
pub fn (b mut Builder) compile_js() {
pub fn (mut b Builder) compile_js() {
// TODO files << b.get_builtin_files()
files := b.get_user_files()
b.set_module_lookup_paths()

View File

@ -1,9 +1,7 @@
module builder
import (
os
time
)
import os
import time
fn (v &Builder) generate_hotcode_reloading_declarations() {
/*

View File

@ -1,15 +1,13 @@
module builder
import (
time
os
v.parser
v.pref
v.gen
v.gen.x64
)
import time
import os
import v.parser
import v.pref
import v.gen
import v.gen.x64
pub fn (b mut Builder) build_x64(v_files []string, out_file string) {
pub fn (mut b Builder) build_x64(v_files []string, out_file string) {
$if !linux {
println('v -x64 can only generate Linux binaries for now')
println('You are not on a Linux system, so you will not ' + 'be able to run the resulting executable')
@ -30,7 +28,7 @@ pub fn (b mut Builder) build_x64(v_files []string, out_file string) {
b.info('x64 GEN: ${gen_time}ms')
}
pub fn (b mut Builder) compile_x64() {
pub fn (mut b Builder) compile_x64() {
// v.files << v.v_files_from_dir(os.join_path(v.pref.vlib_path,'builtin','bare'))
files := [ b.pref.path]
b.set_module_lookup_paths()

View File

@ -3,16 +3,14 @@
// that can be found in the LICENSE file.
module checker
import (
v.ast
v.depgraph
v.table
v.token
v.pref
v.util
v.scanner
os
)
import v.ast
import v.depgraph
import v.table
import v.token
import v.pref
import v.util
import v.scanner
import os
const (
max_nr_errors = 300
@ -46,14 +44,14 @@ pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker {
}
}
pub fn (c mut Checker) check(ast_file ast.File) {
pub fn (mut c Checker) check(ast_file ast.File) {
c.file = ast_file
for stmt in ast_file.stmts {
c.stmt(stmt)
}
}
pub fn (c mut Checker) check2(ast_file ast.File) []scanner.Error {
pub fn (mut c Checker) check2(ast_file ast.File) []scanner.Error {
c.file = ast_file
for stmt in ast_file.stmts {
c.stmt(stmt)
@ -61,7 +59,7 @@ pub fn (c mut Checker) check2(ast_file ast.File) []scanner.Error {
return c.errors
}
pub fn (c mut Checker) check_files(ast_files []ast.File) {
pub fn (mut c Checker) check_files(ast_files []ast.File) {
mut has_main_fn := false
for file in ast_files {
c.check(file)
@ -90,7 +88,7 @@ const (
// do checks specific to files in main module
// returns `true` if a main function is in the file
fn (c mut Checker) check_file_in_main(file ast.File) bool {
fn (mut c Checker) check_file_in_main(file ast.File) bool {
mut has_main_fn := false
for stmt in file.stmts {
match stmt {
@ -122,7 +120,8 @@ fn (c mut Checker) check_file_in_main(file ast.File) bool {
}
if it.ctdefine.len > 0 {
if it.return_type != table.void_type {
c.error('only functions that do NOT return values can have `[if ${it.ctdefine}]` tags', it.pos)
c.error('only functions that do NOT return values can have `[if ${it.ctdefine}]` tags',
it.pos)
}
}
}
@ -156,7 +155,7 @@ fn (c mut Checker) check_file_in_main(file ast.File) bool {
return has_main_fn
}
pub fn (c mut Checker) struct_decl(decl ast.StructDecl) {
pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
splitted_full_name := decl.name.split('.')
is_builtin := splitted_full_name[0] == 'builtin'
name := splitted_full_name.last()
@ -168,7 +167,6 @@ pub fn (c mut Checker) struct_decl(decl ast.StructDecl) {
}
c.error('struct name must begin with capital letter', pos)
}
for fi, _ in decl.fields {
if decl.fields[fi].has_default_expr {
c.expected_type = decl.fields[fi].typ
@ -179,17 +177,15 @@ pub fn (c mut Checker) struct_decl(decl ast.StructDecl) {
field_name := decl.fields[fi].name
fet_name := field_expr_type_sym.name
ft_name := field_type_sym.name
c.error('default expression for field `${field_name}` '+
'has type `${fet_name}`, but should be `${ft_name}`',
decl.fields[fi].default_expr.position()
)
c.error('default expression for field `${field_name}` ' + 'has type `${fet_name}`, but should be `${ft_name}`',
decl.fields[fi].default_expr.position())
}
}
}
// && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && Sp.tok.lit in table.builtin_type_names))
}
pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
pub fn (mut c Checker) struct_init(struct_init mut ast.StructInit) table.Type {
// typ := c.table.find_type(struct_init.typ.typ.name) or {
// c.error('unknown struct: $struct_init.typ.typ.name', struct_init.pos)
// panic('')
@ -203,7 +199,6 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
struct_init.typ = c.expected_type
}
type_sym := c.table.get_type_symbol(struct_init.typ)
// println('check struct $typ_sym.name')
match type_sym.kind {
.placeholder {
@ -239,7 +234,8 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
}
}
if !exists {
c.error('unknown field `$field.name` in struct literal of type `$type_sym.name`', field.pos)
c.error('unknown field `$field.name` in struct literal of type `$type_sym.name`',
field.pos)
continue
}
if field_name in inited_fields {
@ -253,7 +249,8 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
expr_type_sym := c.table.get_type_symbol(expr_type)
field_type_sym := c.table.get_type_symbol(info_field.typ)
if !c.table.check(expr_type, info_field.typ) {
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`', field.pos)
c.error('cannot assign `$expr_type_sym.name` as `$field_type_sym.name` for field `$info_field.name`',
field.pos)
}
struct_init.fields[i].typ = expr_type
struct_init.fields[i].expected_type = info_field.typ
@ -274,7 +271,7 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
return struct_init.typ
}
pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
// println('checker: infix expr(op $infix_expr.op.str())')
c.expected_type = table.void_type
left_type := c.expr(infix_expr.left)
@ -318,12 +315,14 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
if right.kind == .array {
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
if left.kind != right_sym.kind {
c.error('the data type on the left of `in` does not match the array item type', infix_expr.pos)
c.error('the data type on the left of `in` does not match the array item type',
infix_expr.pos)
}
} else if right.kind == .map {
key_sym := c.table.get_type_symbol(right.map_info().key_type)
if left.kind != key_sym.kind {
c.error('the data type on the left of `in` does not match the map key type', infix_expr.pos)
c.error('the data type on the left of `in` does not match the map key type',
infix_expr.pos)
}
} else if right.kind == .string {
if left.kind != .string {
@ -336,10 +335,11 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
}
if infix_expr.op in [.amp, .pipe, .xor] {
if !left.is_int() {
c.error('left type of `${infix_expr.op.str()}` cannot be non-integer type $left.name', infix_expr.left.position())
}
else if !right.is_int() {
c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name', infix_expr.right.position())
c.error('left type of `${infix_expr.op.str()}` cannot be non-integer type $left.name',
infix_expr.left.position())
} else if !right.is_int() {
c.error('right type of `${infix_expr.op.str()}` cannot be non-integer type $right.name',
infix_expr.right.position())
}
}
if infix_expr.op == .mod {
@ -376,7 +376,8 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
if left_type == table.void_type || right_type == table.void_type {
return table.void_type
}
c.error('infix expr: cannot use `$right.name` (right expression) as `$left.name`', infix_expr.pos)
c.error('infix expr: cannot use `$right.name` (right expression) as `$left.name`',
infix_expr.pos)
}
if infix_expr.op.is_relational() {
return table.bool_type
@ -384,7 +385,7 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
return left_type
}
fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
fn (mut c Checker) assign_expr(assign_expr mut ast.AssignExpr) {
c.expected_type = table.void_type
left_type := c.expr(assign_expr.left)
c.expected_type = left_type
@ -402,7 +403,8 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
scope := c.file.scope.innermost(assign_expr.pos.pos)
if v := scope.find_var(it.name) {
if !v.is_mut {
c.error('`$it.name` is immutable, declare it with `mut` to assign to it', assign_expr.pos)
c.error('`$it.name` is immutable, declare it with `mut` to assign to it',
assign_expr.pos)
}
}
}
@ -414,33 +416,33 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
.plus_assign {
if !left.is_number() && left_type != table.string_type && !left.is_pointer() {
c.error('operator += not defined on left operand type `$left.name`', assign_expr.left.position())
}
else if !right.is_number() && right_type != table.string_type && !right.is_pointer() {
} else if !right.is_number() && right_type != table.string_type && !right.is_pointer() {
c.error('operator += not defined on right operand type `$right.name`', assign_expr.val.position())
}
}
.minus_assign {
if !left.is_number() && !left.is_pointer() {
c.error('operator -= not defined on left operand type `$left.name`', assign_expr.left.position())
}
else if !right.is_number() && !right.is_pointer() {
} else if !right.is_number() && !right.is_pointer() {
c.error('operator -= not defined on right operand type `$right.name`', assign_expr.val.position())
}
}
.mult_assign, .div_assign {
if !left.is_number() {
c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`', assign_expr.left.position())
}
else if !right.is_number() {
c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`', assign_expr.val.position())
c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`',
assign_expr.left.position())
} else if !right.is_number() {
c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`',
assign_expr.val.position())
}
}
.and_assign, .or_assign, .xor_assign, .mod_assign, .left_shift_assign, .right_shift_assign {
if !left.is_int() {
c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`', assign_expr.left.position())
}
else if !right.is_int() {
c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`', assign_expr.val.position())
c.error('operator ${assign_expr.op.str()} not defined on left operand type `$left.name`',
assign_expr.left.position())
} else if !right.is_int() {
c.error('operator ${assign_expr.op.str()} not defined on right operand type `$right.name`',
assign_expr.val.position())
}
}
else {}
@ -455,7 +457,7 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
c.check_expr_opt_call(assign_expr.val, right_type, true)
}
pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
pub fn (mut c Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
c.stmts(call_expr.or_block.stmts)
if call_expr.is_method {
return c.call_method(call_expr)
@ -463,7 +465,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
return c.call_fn(call_expr)
}
pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
pub fn (mut c Checker) call_method(call_expr mut ast.CallExpr) table.Type {
left_type := c.expr(call_expr.left)
call_expr.left_type = left_type
left_type_sym := c.table.get_type_symbol(left_type)
@ -496,13 +498,15 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
return info.elem_type
}
if method := c.table.type_find_method(left_type_sym, method_name) {
if !method.is_pub && !c.is_builtin_mod && !c.pref.is_test && left_type_sym.mod != c.mod && left_type_sym.mod != '' { // method.mod != c.mod {
if !method.is_pub && !c.is_builtin_mod && !c.pref.is_test && left_type_sym.mod != c.mod &&
left_type_sym.mod != '' { // method.mod != c.mod {
// If a private method is called outside of the module
// its receiver type is defined in, show an error.
// println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
}
if method.return_type == table.void_type && method.ctdefine.len > 0 && method.ctdefine !in c.pref.compile_defines {
if method.return_type == table.void_type && method.ctdefine.len > 0 && method.ctdefine !in
c.pref.compile_defines {
call_expr.should_be_skipped = true
}
nr_args := if method.args.len == 0 { 0 } else { method.args.len - 1 }
@ -528,7 +532,8 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
}
arg_typ := c.expr(arg.expr)
call_expr.args[i].typ = arg_typ
if method.is_variadic && arg_typ.flag_is(.variadic) && call_expr.args.len-1 > i {
if method.is_variadic && arg_typ.flag_is(.variadic) && call_expr.args.len - 1 >
i {
c.error('when forwarding a varg variable, it must be the final argument', call_expr.pos)
}
}
@ -568,7 +573,7 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
return table.void_type
}
pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
pub fn (mut c Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
if call_expr.name == 'panic' {
c.returns = true
}
@ -620,11 +625,9 @@ pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
return table.void_type
}
call_expr.return_type = f.return_type
if f.return_type == table.void_type && f.ctdefine.len > 0 && f.ctdefine !in c.pref.compile_defines {
call_expr.should_be_skipped = true
}
if f.is_c || call_expr.is_c || f.is_js || call_expr.is_js {
for arg in call_expr.args {
c.expr(arg.expr)
@ -683,7 +686,7 @@ pub fn (c mut Checker) call_fn(call_expr mut ast.CallExpr) table.Type {
return f.return_type
}
pub fn (c mut Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) {
pub fn (mut c Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) {
match x {
ast.CallExpr {
if it.return_type.flag_is(.optional) {
@ -694,7 +697,7 @@ pub fn (c mut Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_retu
}
}
pub fn (c mut Checker) check_or_block(call_expr mut ast.CallExpr, ret_type table.Type, is_ret_used bool) {
pub fn (mut c Checker) check_or_block(call_expr mut ast.CallExpr, ret_type table.Type, is_ret_used bool) {
if !call_expr.or_block.is_used {
c.error('${call_expr.name}() returns an option, but you missed to add an `or {}` block to it',
call_expr.pos)
@ -746,34 +749,22 @@ pub fn (c mut Checker) check_or_block(call_expr mut ast.CallExpr, ret_type table
fn is_expr_panic_or_exit(expr ast.Expr) bool {
match expr {
ast.CallExpr {
return it.name in ['panic', 'exit']
}
else {
return false
}
ast.CallExpr { return it.name in ['panic', 'exit'] }
else { return false }
}
}
// TODO: merge to check_or_block when v can handle it
pub fn (c mut Checker) is_last_or_block_stmt_valid(stmt ast.Stmt) bool {
pub fn (mut c Checker) is_last_or_block_stmt_valid(stmt ast.Stmt) bool {
return match stmt {
ast.Return {
true
}
ast.BranchStmt {
true
}
ast.ExprStmt {
true
}
else {
false
}
ast.Return { true }
ast.BranchStmt { true }
ast.ExprStmt { true }
else { false }
}
}
pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.Type {
pub fn (mut c Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.Type {
typ := c.expr(selector_expr.expr)
if typ == table.void_type_idx {
c.error('unknown selector expression', selector_expr.pos)
@ -801,7 +792,7 @@ pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.T
}
// TODO: non deferred
pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
pub fn (mut c Checker) return_stmt(return_stmt mut ast.Return) {
c.expected_type = c.fn_return_type
if return_stmt.exprs.len > 0 && c.fn_return_type == table.void_type {
c.error('too many arguments to return, current function does not return anything',
@ -842,12 +833,13 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
got_typ_sym := c.table.get_type_symbol(got_typ)
exp_typ_sym := c.table.get_type_symbol(exp_typ)
pos := return_stmt.exprs[i].position()
c.error('cannot use `$got_typ_sym.name` as type `$exp_typ_sym.name` in return argument', pos)
c.error('cannot use `$got_typ_sym.name` as type `$exp_typ_sym.name` in return argument',
pos)
}
}
}
pub fn (c mut Checker) enum_decl(decl ast.EnumDecl) {
pub fn (mut c Checker) enum_decl(decl ast.EnumDecl) {
for field in decl.fields {
if field.has_expr {
match field.expr {
@ -871,13 +863,14 @@ pub fn (c mut Checker) enum_decl(decl ast.EnumDecl) {
}
}
pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
// check variablename for beginning with capital letter 'Abc'
for ident in assign_stmt.left {
is_decl := assign_stmt.op == .decl_assign
if is_decl && scanner.contains_capital(ident.name) {
c.error('variable names cannot contain uppercase letters, use snake_case instead', ident.pos)
c.error('variable names cannot contain uppercase letters, use snake_case instead',
ident.pos)
} else if is_decl && ident.kind != .blank_ident {
if ident.name.starts_with('__') {
c.error('variable names cannot start with `__`', ident.pos)
@ -888,9 +881,7 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
// multi return
match assign_stmt.right[0] {
ast.CallExpr {}
else {
c.error('assign_stmt: expected call', assign_stmt.pos)
}
else { c.error('assign_stmt: expected call', assign_stmt.pos) }
}
right_type := c.expr(assign_stmt.right[0])
right_type_sym := c.table.get_type_symbol(right_type)
@ -969,7 +960,7 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
// c.assigned_var_name = ''
}
pub fn (c mut Checker) array_init(array_init mut ast.ArrayInit) table.Type {
pub fn (mut c Checker) array_init(array_init mut ast.ArrayInit) table.Type {
// println('checker: array init $array_init.pos.line_nr $c.file.path')
mut elem_type := table.void_type
// []string - was set in parser
@ -1056,15 +1047,13 @@ fn const_int_value(cfield ast.ConstField) ?int {
fn is_const_integer(cfield ast.ConstField) ?ast.IntegerLiteral {
match cfield.expr {
ast.IntegerLiteral {
return *it
}
ast.IntegerLiteral { return *it }
else {}
}
return none
}
fn (c mut Checker) stmt(node ast.Stmt) {
fn (mut c Checker) stmt(node ast.Stmt) {
// c.expected_type = table.void_type
match mut node {
ast.AssertStmt {
@ -1151,8 +1140,8 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.expected_type = table.void_type
c.fn_return_type = it.return_type
c.stmts(it.stmts)
if !it.is_c && !it.is_js && !it.no_body && it.return_type != table.void_type && !c.returns &&
!(it.name in ['panic', 'exit']) {
if !it.is_c && !it.is_js && !it.no_body && it.return_type != table.void_type &&
!c.returns && !(it.name in ['panic', 'exit']) {
c.error('missing return at end of function `$it.name`', it.pos)
}
c.returns = false
@ -1198,12 +1187,8 @@ fn (c mut Checker) stmt(node ast.Stmt) {
sym := c.table.get_type_symbol(typ)
if it.key_var.len > 0 {
key_type := match sym.kind {
.map {
sym.map_info().key_type
}
else {
table.int_type
}
.map { sym.map_info().key_type }
else { table.int_type }
}
it.key_type = key_type
scope.update_var_type(it.key_var, key_type)
@ -1233,7 +1218,6 @@ fn (c mut Checker) stmt(node ast.Stmt) {
c.mod = it.name
c.is_builtin_mod = it.name == 'builtin'
}
// ast.GlobalDecl {}
ast.Return {
c.returns = true
@ -1259,7 +1243,7 @@ fn is_call_expr(expr ast.Expr) bool {
}
}
fn (c mut Checker) stmts(stmts []ast.Stmt) {
fn (mut c Checker) stmts(stmts []ast.Stmt) {
c.expected_type = table.void_type
for stmt in stmts {
c.stmt(stmt)
@ -1267,7 +1251,7 @@ fn (c mut Checker) stmts(stmts []ast.Stmt) {
c.expected_type = table.void_type
}
pub fn (c mut Checker) expr(node ast.Expr) table.Type {
pub fn (mut c Checker) expr(node ast.Expr) table.Type {
match mut node {
ast.ArrayInit {
return c.array_init(mut it)
@ -1418,7 +1402,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
return table.void_type
}
pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
pub fn (mut c Checker) ident(ident mut ast.Ident) table.Type {
if ident.name == c.var_decl_name { // c.checked_ident {
c.error('unresolved: `$ident.name`', ident.pos)
return table.void_type
@ -1524,7 +1508,7 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type {
return table.void_type
}
pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type {
pub fn (mut c Checker) match_expr(node mut ast.MatchExpr) table.Type {
node.is_expr = c.expected_type != table.void_type
node.expected_type = c.expected_type
cond_type := c.expr(node.cond)
@ -1583,15 +1567,9 @@ fn (mut c Checker) match_exprs(node mut ast.MatchExpr, type_sym table.TypeSymbol
for expr in branch.exprs {
mut key := ''
match expr {
ast.Type {
key = c.table.type_to_str(it.typ)
}
ast.EnumVal {
key = it.val
}
else {
key = expr.str()
}
ast.Type { key = c.table.type_to_str(it.typ) }
ast.EnumVal { key = it.val }
else { key = expr.str() }
}
val := if key in branch_exprs { branch_exprs[key] } else { 0 }
if val == 1 {
@ -1646,7 +1624,7 @@ fn (mut c Checker) match_exprs(node mut ast.MatchExpr, type_sym table.TypeSymbol
}
}
pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
pub fn (mut c Checker) if_expr(node mut ast.IfExpr) table.Type {
if c.expected_type != table.void_type {
// | c.assigned_var_name != '' {
// sym := c.table.get_type_symbol(c.expected_type)
@ -1656,7 +1634,8 @@ pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
node.typ = table.void_type
for i, branch in node.branches {
if branch.cond is ast.ParExpr {
c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.', branch.pos)
c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.',
branch.pos)
}
typ := c.expr(branch.cond)
if i < node.branches.len - 1 || !node.has_else {
@ -1686,7 +1665,7 @@ pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
return table.bool_type
}
pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type {
pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type {
/*
match node.expr {
ast.IdentVar {
@ -1705,7 +1684,7 @@ pub fn (c mut Checker) postfix_expr(node ast.PostfixExpr) table.Type {
return typ
}
pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type {
pub fn (mut c Checker) index_expr(node mut ast.IndexExpr) table.Type {
typ := c.expr(node.left)
node.left_type = typ
mut is_range := false // TODO is_range := node.index is ast.RangeExpr
@ -1754,7 +1733,7 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type {
// `.green` or `Color.green`
// If a short form is used, `expected_type` needs to be an enum
// with this value.
pub fn (c mut Checker) enum_val(node mut ast.EnumVal) table.Type {
pub fn (mut c Checker) enum_val(node mut ast.EnumVal) table.Type {
typ_idx := if node.enum_name == '' {
c.expected_type.idx()
} else { //
@ -1781,7 +1760,7 @@ pub fn (c mut Checker) enum_val(node mut ast.EnumVal) table.Type {
return typ
}
pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type {
pub fn (mut c Checker) map_init(node mut ast.MapInit) table.Type {
// `x ;= map[string]string` - set in parser
if node.typ != 0 {
info := c.table.get_type_symbol(node.typ).map_info()
@ -1819,19 +1798,19 @@ pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type {
return map_type
}
pub fn (c mut Checker) warn(s string, pos token.Position) {
pub fn (mut c Checker) warn(s string, pos token.Position) {
allow_warnings := !c.pref.is_prod // allow warnings only in dev builds
c.warn_or_error(s, pos, allow_warnings) // allow warnings only in dev builds
}
pub fn (c mut Checker) error(message string, pos token.Position) {
pub fn (mut c Checker) error(message string, pos token.Position) {
if c.pref.is_verbose {
print_backtrace()
}
c.warn_or_error(message, pos, false)
}
fn (c mut Checker) warn_or_error(message string, pos token.Position, warn bool) {
fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool) {
// add backtrace to issue struct, how?
// if c.pref.is_verbose {
// print_backtrace()

View File

@ -1,7 +1,5 @@
import (
v.table
v.doc
)
import v.table
import v.doc
fn test_vdoc() {
table := table.new_table()

View File

@ -3,12 +3,10 @@
// that can be found in the LICENSE file.
module eval
import (
v.ast
v.checker
v.table
v.pref
)
import v.ast
import v.checker
import v.table
import v.pref
pub type Object = int | string
@ -23,7 +21,7 @@ pub struct Var {
value Object
}
pub fn (e mut Eval) eval(file ast.File, table &table.Table) string {
pub fn (mut e Eval) eval(file ast.File, table &table.Table) string {
vpref := &pref.Preferences{}
e.table = table
mut res := ''
@ -36,29 +34,24 @@ pub fn (e mut Eval) eval(file ast.File, table &table.Table) string {
fn print_object(o Object) {
match o {
int {
println(it)
}
else {
println('unknown object')
}
int { println(it) }
else { println('unknown object') }
}
}
pub fn (o Object) str() string {
match o {
int {
return it.str()
}
else {
println('unknown object')
}
int { return it.str() }
else { println('unknown object') }
}
return ''
}
fn (e mut Eval) stmt(node ast.Stmt) string {
fn (mut e Eval) stmt(node ast.Stmt) string {
match node {
ast.AssignStmt {
// TODO; replaced VarDecl
}
ast.ExprStmt {
o := e.expr(it.expr)
print('out: ')
@ -68,9 +61,6 @@ fn (e mut Eval) stmt(node ast.Stmt) string {
// ast.StructDecl {
// println('s decl')
// }
ast.AssignStmt {
// TODO; replaced VarDecl
}
// ast.VarDecl {
// e.vars[it.name] = Var{
// value: e.expr(it.expr)
@ -81,7 +71,7 @@ fn (e mut Eval) stmt(node ast.Stmt) string {
return '>>'
}
fn (e mut Eval) expr(node ast.Expr) Object {
fn (mut e Eval) expr(node ast.Expr) Object {
match node {
ast.IntegerLiteral {
return it.val
@ -98,12 +88,8 @@ fn (e mut Eval) expr(node ast.Expr) Object {
left := e.expr(it.left) as int
right := e.expr(it.right) as int
match it.op {
.plus {
return left + right
}
.mul {
return left * right
}
.plus { return left + right }
.mul { return left * right }
else {}
}
}

View File

@ -247,23 +247,7 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
}
}
ast.FnDecl {
// println('$it.name find_comment($it.pos.line_nr)')
// f.find_comment(it.pos.line_nr)
s := it.str(f.table)
// f.write(it.str(f.table))
f.write(s.replace(f.cur_mod + '.', '')) // `Expr` instead of `ast.Expr` in mod ast
if !it.is_c && !it.is_js {
f.writeln(' {')
f.stmts(it.stmts)
f.writeln('}\n')
} else {
f.writeln('\n')
}
// Mark all function's used type so that they are not removed from imports
for arg in it.args {
f.mark_types_module_as_used(arg.typ)
}
f.mark_types_module_as_used(it.return_type)
f.fn_decl(it)
}
ast.ForCStmt {
f.write('for ')
@ -320,6 +304,11 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
f.expr(it.expr)
}
}
ast.GoStmt {
f.write('go ')
f.expr(it.call_expr)
f.writeln('')
}
ast.GotoLabel {
f.writeln('$it.name:')
}
@ -374,12 +363,6 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
f.stmts(it.stmts)
f.writeln('}')
}
else {
eprintln('fmt stmt: unhandled node ' + typeof(node))
if typeof(node) != 'unknown v.ast.Expr' {
exit(1)
}
}
}
}
@ -469,6 +452,9 @@ fn (f &Fmt) type_to_str(t table.Type) string {
fn (mut f Fmt) expr(node ast.Expr) {
match node {
ast.AnonFn {
f.fn_decl(it.decl)
}
ast.ArrayInit {
if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type {
// `x := []string`
@ -478,25 +464,29 @@ fn (mut f Fmt) expr(node ast.Expr) {
// type_sym := f.table.get_type_symbol(it.typ)
f.write('[')
mut inc_indent := false
mut line_nr := node.position().line_nr // to have the same newlines between array elements
mut last_line_nr := node.position().line_nr // to have the same newlines between array elements
for i, expr in it.exprs {
pos := expr.position()
if i == 0 && line_nr < pos.line_nr {
f.writeln('')
line_nr := expr.position().line_nr
if last_line_nr < line_nr {
if !inc_indent {
f.indent++
inc_indent = true
}
if i > 0 && it.exprs.len > 1 {
f.wrap_long_line()
f.writeln('')
}
is_new_line := last_line_nr < line_nr || f.wrap_long_line()
if !is_new_line && i > 0 {
f.write(' ')
}
f.expr(expr)
if line_nr < pos.line_nr {
// Previous element was on a different line, add a newline
if i == it.exprs.len - 1 {
if is_new_line {
f.writeln('')
} else if i < it.exprs.len - 1 {
}
} else {
f.write(',')
}
line_nr = pos.line_nr
last_line_nr = line_nr
}
if inc_indent {
f.indent--
@ -541,6 +531,14 @@ fn (mut f Fmt) expr(node ast.Expr) {
ast.CharLiteral {
f.write('`$it.val`')
}
ast.ConcatExpr {
for i, val in it.vals {
if i != 0 {
f.write(' + ')
}
f.expr(val)
}
}
ast.EnumVal {
name := short_module(it.enum_name)
f.write(name + '.' + it.val)
@ -563,6 +561,10 @@ fn (mut f Fmt) expr(node ast.Expr) {
}
}
}
ast.IfGuardExpr {
f.write(it.var_name + ' := ')
f.expr(it.expr)
}
ast.InfixExpr {
f.expr(it.left)
f.write(' $it.op.str() ')
@ -606,9 +608,10 @@ fn (mut f Fmt) expr(node ast.Expr) {
ast.None {
f.write('none')
}
ast.IfGuardExpr {
f.write(it.var_name + ' := ')
f.expr(it.expr)
ast.OrExpr {
// shouldn't happen, an or expression
// is always linked to a call expr
panic('fmt: OrExpr should to linked to CallExpr')
}
ast.ParExpr {
f.write('(')
@ -643,7 +646,7 @@ fn (mut f Fmt) expr(node ast.Expr) {
f.write(')')
}
ast.StringLiteral {
if it.val.contains("'") {
if it.val.contains("'") && !it.val.contains('"') {
f.write('"$it.val"')
} else {
f.write("'$it.val'")
@ -708,23 +711,19 @@ fn (mut f Fmt) expr(node ast.Expr) {
f.expr(it.expr)
f.write(')')
}
else {
eprintln('fmt expr: unhandled node ' + typeof(node))
if typeof(node) != 'unknown v.ast.Expr' {
exit(1)
}
}
}
}
fn (mut f Fmt) wrap_long_line() {
if f.line_len > max_len {
fn (mut f Fmt) wrap_long_line() bool {
if f.line_len <= max_len {
return false
}
if f.out.buf[f.out.buf.len - 1] == ` ` {
f.out.go_back(1)
}
f.write('\n' + tabs[f.indent + 1])
f.line_len = 0
}
return true
}
fn (mut f Fmt) call_args(args []ast.CallArg) {
@ -743,7 +742,7 @@ fn (mut f Fmt) call_args(args []ast.CallArg) {
}
fn (mut f Fmt) or_expr(or_block ast.OrExpr) {
if or_block.stmts.len > 0 {
if or_block.is_used {
f.writeln(' or {')
f.stmts(or_block.stmts)
f.write('}')
@ -772,9 +771,32 @@ fn (mut f Fmt) comment(node ast.Comment) {
f.writeln(line)
f.empty_line = false
}
f.empty_line = true
f.writeln('*/')
}
fn (mut f Fmt) fn_decl(node ast.FnDecl) {
// println('$it.name find_comment($it.pos.line_nr)')
// f.find_comment(it.pos.line_nr)
s := node.str(f.table)
f.write(s.replace(f.cur_mod + '.', '')) // `Expr` instead of `ast.Expr` in mod ast
if !node.is_c && !node.is_js {
f.writeln(' {')
f.stmts(node.stmts)
f.write('}')
if !node.is_anon {
f.writeln('\n')
}
} else {
f.writeln('\n')
}
// Mark all function's used type so that they are not removed from imports
for arg in node.args {
f.mark_types_module_as_used(arg.typ)
}
f.mark_types_module_as_used(node.return_type)
}
// foo.bar.fn() => bar.fn()
fn short_module(name string) string {
if !name.contains('.') {
@ -822,8 +844,8 @@ fn (mut f Fmt) if_expr(it ast.IfExpr) {
fn (mut f Fmt) call_expr(node ast.CallExpr) {
if node.is_method {
match node.left {
ast.Ident {
if node.left is ast.Ident {
it := node.left as ast.Ident
// `time.now()` without `time imported` is processed as a method call with `time` being
// a `node.left` expression. Import `time` automatically.
// TODO fetch all available modules
@ -840,8 +862,6 @@ fn (mut f Fmt) call_expr(node ast.CallExpr) {
// }
}
}
else {}
}
f.expr(node.left)
f.write('.' + node.name + '(')
f.call_args(node.args)
@ -882,6 +902,9 @@ fn (mut f Fmt) match_expr(it ast.MatchExpr) {
single_line = false
break
}
} else if stmt is ast.Comment {
single_line = false
break
}
}
for i, branch in it.branches {

View File

@ -1,13 +1,11 @@
import (
os
term
benchmark
v.ast
v.fmt
v.parser
v.table
v.pref
)
import os
import term
import benchmark
import v.ast
import v.fmt
import v.parser
import v.table
import v.pref
const (
error_missing_vexe = 1
@ -45,7 +43,9 @@ fn test_fmt() {
continue
}
table := table.new_table()
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{parent: 0})
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{
parent: 0
})
result_ocontent := fmt.fmt(file_ast, table)
if expected_ocontent != result_ocontent {
fmt_bench.fail()

View File

@ -1,13 +1,11 @@
import (
os
term
benchmark
v.ast
v.fmt
v.parser
v.table
v.pref
)
import os
import term
import benchmark
import v.ast
import v.fmt
import v.parser
import v.table
import v.pref
const (
error_missing_vexe = 1
@ -47,7 +45,9 @@ fn test_fmt() {
continue
}
table := table.new_table()
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{parent: 0})
file_ast := parser.parse_file(ipath, table, .parse_comments, &pref.Preferences{}, &ast.Scope{
parent: 0
})
result_ocontent := fmt.fmt(file_ast, table)
if expected_ocontent != result_ocontent {
fmt_bench.fail()

View File

@ -0,0 +1,24 @@
fn has_anon_fn() {
an_fn := fn () {
println('Hello there !')
}
an_fn_w_param := fn (s string) {
println('I received $s')
}
an_fn_w_multi_params := fn (s1, s2, s3 string) {
println('I received $s1, $s2, $s3')
}
an_fn_w_multi_params2 := fn (s string, i int) {
println('I received $s, $i')
}
fn_w_var_args := fn (ss ...string) {
for s in ss {
println('yo $s')
}
}
an_fn()
an_fn_w_param('a gift')
an_fn_w_multi_params('one', 'two', 'three')
an_fn_w_multi_params2('one', 1)
fn_w_var_args('one arg', 'two args', 'three args')
}

View File

@ -0,0 +1,23 @@
fn has_anon_fn() {
an_fn := fn() {
println('Hello there !')
}
an_fn_w_param := fn ( s string )
{
println('I received $s')
}
an_fn_w_multi_params := fn (s1, s2, s3 string) {
println('I received $s1, $s2, $s3')
}
an_fn_w_multi_params2 :=fn (s string, i int) {
println('I received $s, $i')
}
fn_w_var_args := fn (ss ...string) {
for s in ss {
println('yo $s')
}
} an_fn()
an_fn_w_param('a gift') an_fn_w_multi_params('one', 'two', 'three')
an_fn_w_multi_params2( 'one', 1)
fn_w_var_args('one arg', 'two args', 'three args')
}

View File

@ -5,8 +5,9 @@ fn make_flag(a, b, c string) string {
fn main() {
// Set up flags
expected_flags := [
make_flag('solaris', '-L', '/opt/local/lib')
make_flag('darwin', '-framework', 'Cocoa')
make_flag('solaris', '-L', '/opt/local/lib'),
make_flag('darwin', '-framework', 'Cocoa'),
make_flag('windows', '-l', 'gdi32')
]
_ := expected_flags
}

View File

@ -1,10 +1,12 @@
fn fn_contains_index_expr() {
arr := [1, 2, 3, 4, 5]
a := 1 in arr[0..]
b := 1 in arr[..2]
c := 1 in arr[1..3]
_ := a
_ := 1 in arr[..2]
_ := 1 in arr[1..3]
d := arr[2]
e := arr[2..]
f := arr[..2]
g := arr[1..3]
_ := d
_ := arr[2..]
_ := arr[..2]
_ := arr[1..3]
}

View File

@ -3,10 +3,12 @@
fn fn_contains_index_expr() {
arr := [1, 2, 3, 4, 5]
a := 1 in arr[ 0.. ]
b := 1 in arr[ ..2 ]
c := 1 in arr[1..3]
_ := a
_ := 1 in arr[ ..2 ]
_ := 1 in arr[1..3]
d := arr[2]
e := arr[2 ..]
f := arr[.. 2 ]
g := arr[ 1 .. 3]
_ := d
_ := arr[2 ..]
_ := arr[.. 2 ]
_ := arr[ 1 .. 3]
}

View File

@ -1,7 +1,8 @@
fn test_as() {
a := sum_expr() as Bar
_ := a
}
fn test_cast() {
f := f32(0)
_ := f32(0)
}

View File

@ -1,7 +1,8 @@
fn test_as() {
a := sum_expr() as Bar
_ := a
}
fn test_cast() {
f := f32(0)
_ := f32(0)
}

View File

@ -0,0 +1,6 @@
fn concatenation_of_strings() {
_ := 'Simple' + 'Concat'
_ := 'Hello' + ' ' + 'World' + '!'
_ := 'There' + ' ' + 'so' + ' ' + 'many' + ' ' + 'words' + ' ' + 'they' + ' ' + "don't" +
' ' + 'fit' + ' ' + 'in' + ' ' + 'one' + ' ' + 'line'
}

View File

@ -0,0 +1,7 @@
fn concatenation_of_strings() {
_ := 'Simple' + 'Concat'
_ := 'Hello'
+ ' ' +
'World' + '!'
_ := 'There' + ' ' + 'so' + ' ' + 'many' + ' ' + 'words' + ' ' + 'they' + ' ' + "don't" + ' ' + 'fit' + ' ' + 'in' + ' ' + 'one' + ' ' + 'line'
}

View File

@ -8,5 +8,5 @@ fn fn_with_if_else() {
}
fn fn_with_if_else_oneline() {
x := if true { 1 } else { 2 }
_ := if true { 1 } else { 2 }
}

View File

@ -6,5 +6,5 @@ fn fn_with_if_else() {
}
fn fn_with_if_else_oneline() {
x := if true { 1 } else { 2 }
_ := if true { 1 } else { 2 }
}

View File

@ -2,6 +2,21 @@ const (
pi = 3.14
phi = 1.618
eulers = 2.7182
supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
one_line_supported = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
another_const = [
'a', 'b',
'c', 'd', 'e',
'f'
]
)
const (
i_am_a_very_long_constant_name_so_i_stand_alone_and_my_length_is_over_90_characters = [
'testforit'
]
)
pub const (

View File

@ -2,8 +2,22 @@ const (
pi=3.14
phi=1.618
eulers=2.7182
supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
one_line_supported = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', 'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
another_const = [
'a', 'b'
'c', 'd', 'e'
'f'
]
)
const (
i_am_a_very_long_constant_name_so_i_stand_alone_and_my_length_is_over_90_characters = ['testforit']
)
pub const (
i_am_pub_const=true
)

View File

@ -0,0 +1,13 @@
fn my_thread() {
println('yo')
}
fn my_thread_with_params(s string) {
println(s)
}
fn my_fn_calling_threads() {
go my_thread()
go my_thread_with_params('yay')
go my_thread_with_params('nono')
}

View File

@ -0,0 +1,16 @@
fn my_thread() {
println('yo')
}
fn my_thread_with_params(s string)
{
println(s)
}
fn my_fn_calling_threads () {
go my_thread()
go my_thread_with_params('yay')
go
my_thread_with_params('nono')
}

View File

@ -9,9 +9,24 @@ fn match_expr() {
fn match_expr_assignment() {
a := 20
b := match a {
_ := match a {
10 { 10 }
5 { 5 }
else { 2 }
}
}
fn match_branch_comment() {
a := 1
match a {
1 {
println('1')
}
2 {
println('2')
}
else {
// do nothing
}
}
}

View File

@ -13,9 +13,24 @@ fn match_expr() {
fn match_expr_assignment() {
a := 20
b := match a {
_ := match a {
10 { 10 }
5 { 5 }
else { 2 }
}
}
fn match_branch_comment() {
a := 1
match a {
1 { println('1') }
2 {
println('2')
}
else {
// do nothing
}
}
}

View File

@ -7,4 +7,16 @@ that is on multiple lines
*/
fn main() {
println('hello')
/*
this comment also
has mutliple lines
but it's difference
is that it is indented !
*/
if true {
/*
this one is even more
indented !
*/
}
}

View File

@ -0,0 +1,11 @@
fn main() {
'Hello world !'
'This is correct !'
"It's okay"
'This is "too"'
// TODO
// 'I\'m not correctly formatted' => "I'm not correctly formatted"
// "\"Everything on the internet is true\" - Albert Einstein, 1965" => '"Everything on the internet is true" - Albert Einstein, 1965'
'I\'m out of idea "_"'
// "Definitely out \":'(\"" => 'Definitely out ":\'("'
}

View File

@ -0,0 +1,11 @@
fn main() {
"Hello world !"
'This is correct !'
"It's okay"
'This is "too"'
// TODO
// 'I\'m not correctly formatted' => "I'm not correctly formatted"
// "\"Everything on the internet is true\" - Albert Einstein, 1965" => '"Everything on the internet is true" - Albert Einstein, 1965'
'I\'m out of idea "_"'
// "Definitely out \":'(\"" => 'Definitely out ":\'("'
}

View File

@ -5,9 +5,9 @@ const (
)
fn test_type_ptr() {
a := &Test{}
b := []&Test
c := &[]&Test
_ := &Test{}
_ := []&Test
_ := &[]&Test
}
struct Test {

View File

@ -14,27 +14,27 @@ import term
const (
c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free', 'panic', 'auto',
'char'
'default'
'do'
'double'
'extern'
'float'
'inline'
'int'
'long'
'register'
'restrict'
'short'
'signed'
'sizeof'
'static'
'switch'
'typedef'
'union'
'unsigned'
'void'
'volatile'
'char',
'default',
'do',
'double',
'extern',
'float',
'inline',
'int',
'long',
'register',
'restrict',
'short',
'signed',
'sizeof',
'static',
'switch',
'typedef',
'union',
'unsigned',
'void',
'volatile',
'while'
]
)
@ -1420,7 +1420,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
g.expr_with_cast(node.right, node.right_type, info.elem_type)
g.write(' })')
}
} else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in [.eq, .ne] {
} else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in
[.eq, .ne] {
// floats should be compared with epsilon
if node.left_type == table.f64_type_idx {
if node.op == .eq {
@ -2378,8 +2379,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
g.write('${str_fn_name}(')
g.expr(expr)
g.write(').str')
}
else if sym.kind == .enum_ {
} else if sym.kind == .enum_ {
is_var := match node.exprs[i] {
ast.SelectorExpr { true }
ast.Ident { true }

View File

@ -1,9 +1,7 @@
import (
os
v.pref
v.builder
term
)
import os
import v.pref
import v.builder
import term
const (
nr_tests = 4
@ -35,8 +33,7 @@ fn test_c_files() {
}
if compare_texts(res, ctext, path) {
println('${term_ok} ${i}')
}
else {
} else {
assert false
}
}
@ -56,7 +53,6 @@ fn compare_texts(a, b, path string) bool {
return false
}
*/
for i, line_a in lines_a {
if i >= lines_b.len {
println(line_a)

View File

@ -102,7 +102,6 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
}
}
}
// Profiling mode? Start counting at the beginning of the function (save current time).
if g.pref.is_prof {
if is_main {
@ -122,7 +121,6 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
g.pcs[g.last_fn_c_name] = fn_profile_counter_name
}
}
g.stmts(it.stmts)
// ////////////
if g.autofree {
@ -267,11 +265,11 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
}
// TODO performance, detect `array` method differently
if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many',
'trim'
'first'
'last'
'clone'
'reverse'
'trim',
'first',
'last',
'clone',
'reverse',
'slice'
] {
// && rec_sym.name == 'array' {
@ -298,8 +296,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.write('/*rec*/*')
}
g.expr(node.left)
is_variadic := node.expected_arg_types.len > 0 &&
node.expected_arg_types[node.expected_arg_types.len -1].flag_is(.variadic)
is_variadic := node.expected_arg_types.len > 0 && node.expected_arg_types[node.expected_arg_types.len -
1].flag_is(.variadic)
if node.args.len > 0 || is_variadic {
g.write(', ')
}
@ -441,8 +439,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
}
fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 &&
expected_types[expected_types.len - 1].flag_is(.variadic)
is_variadic := expected_types.len > 0 && expected_types[expected_types.len - 1].flag_is(.variadic)
is_forwarding_varg := args.len > 0 && args[args.len - 1].typ.flag_is(.variadic)
gen_vargs := is_variadic && !is_forwarding_varg
mut arg_no := 0

View File

@ -1,9 +1,7 @@
module js
import (
strings
v.ast
)
import strings
import v.ast
struct JsDoc {
gen &JsGen
@ -19,30 +17,30 @@ fn new_jsdoc(gen &JsGen) &JsDoc {
}
}
fn (d mut JsDoc) gen_indent() {
fn (mut d JsDoc) gen_indent() {
if d.gen.indents[d.gen.namespace] > 0 && d.empty_line {
d.out.write(tabs[d.gen.indents[d.gen.namespace]])
}
d.empty_line = false
}
fn (d mut JsDoc) write(s string) {
fn (mut d JsDoc) write(s string) {
d.gen_indent()
d.out.write(s)
}
fn (d mut JsDoc) writeln(s string) {
fn (mut d JsDoc) writeln(s string) {
d.gen_indent()
d.out.writeln(s)
d.empty_line = true
}
fn (d mut JsDoc) reset() {
fn (mut d JsDoc) reset() {
d.out = strings.new_builder(20)
d.empty_line = false
}
fn (d mut JsDoc) gen_typ(typ string, name string) string {
fn (mut d JsDoc) gen_typ(typ, name string) string {
d.reset()
d.write('/**')
d.write(' @type {$typ}')
@ -53,13 +51,15 @@ fn (d mut JsDoc) gen_typ(typ string, name string) string {
return d.out.str()
}
fn (d mut JsDoc) gen_ctor(fields []ast.StructField) string {
fn (mut d JsDoc) gen_ctor(fields []ast.StructField) string {
d.reset()
d.writeln('/**')
d.write('* @param {{')
for i, field in fields {
d.write('$field.name: ${d.gen.typ(field.typ)}')
if i < fields.len-1 { d.write(', ') }
if i < fields.len - 1 {
d.write(', ')
}
}
d.writeln('}} values - values for this class fields')
d.writeln('* @constructor')
@ -67,12 +67,14 @@ fn (d mut JsDoc) gen_ctor(fields []ast.StructField) string {
return d.out.str()
}
fn (d mut JsDoc) gen_fn(it ast.FnDecl) string {
fn (mut d JsDoc) gen_fn(it ast.FnDecl) string {
d.reset()
type_name := d.gen.typ(it.return_type)
d.writeln('/**')
for i, arg in it.args {
if it.is_method && i == 0 { continue }
if it.is_method && i == 0 {
continue
}
arg_type_name := d.gen.typ(arg.typ)
is_varg := i == it.args.len - 1 && it.is_variadic
if is_varg {

View File

@ -34,8 +34,9 @@ const (
)
pub fn (mut g Gen) generate_elf_header() {
g.buf << [byte(mag0), mag1
mag2
g.buf << [byte(mag0),
mag1,
mag2,
mag3
]
g.buf << elfclass64 // file class

View File

@ -2,14 +2,13 @@
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module x64
/*
This file is unused right now, since binaries without sections
are generated.
But it will be necessary once we have dynamic linking.
*/
enum SectionType {
null = 0
progbits = 1
@ -31,7 +30,7 @@ struct SectionConfig {
entsize i64
}
fn (g mut Gen) section_header(c SectionConfig) {
fn (mut g Gen) section_header(c SectionConfig) {
g.write32(g.sect_header_name_pos)
g.sect_header_name_pos += c.name.len + 1
g.write32(int(c.typ))
@ -156,4 +155,3 @@ fn genobj() {
})
*/
}

View File

@ -3,11 +3,9 @@
// that can be found in the LICENSE file.
module parser
import (
v.ast
v.pref
v.vmod
)
import v.ast
import v.pref
import v.vmod
const (
supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
@ -26,8 +24,7 @@ fn (mut p Parser) hash() ast.HashStmt {
vmod_file_location := vmod.mod_file_cacher.get(p.file_name_dir)
if vmod_file_location.vmod_file.len == 0 {
// There was no actual v.mod file found.
p.error('To use @VROOT, you need' +
' to have a "v.mod" file in ${p.file_name_dir},' +
p.error('To use @VROOT, you need' + ' to have a "v.mod" file in ${p.file_name_dir},' +
' or in one of its parent folders.')
}
flag = flag.replace('@VROOT', vmod_file_location.vmod_folder)
@ -72,7 +69,8 @@ fn (mut p Parser) comp_if() ast.CompIf {
// `$if os {` for a different target, skip everything inside
// to avoid compilation errors (like including <windows.h> or calling WinAPI fns
// on non-Windows systems)
if !p.scanner.is_fmt && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c {
if !p.scanner.is_fmt && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) &&
!p.pref.output_cross_c {
skip_os = true
p.check(.lcbr)
// p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os')

View File

@ -2,6 +2,7 @@
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module parser
// return true if file being parsed imports `mod`
pub fn (p &Parser) known_import(mod string) bool {
return mod in p.imports

View File

@ -187,7 +187,6 @@ pub fn (mut p Parser) read_first_token() {
p.next()
}
pub fn (mut p Parser) open_scope() {
p.scope = &ast.Scope{
parent: p.scope
@ -638,9 +637,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
name_w_mod := p.prepend_mod(name)
// type cast. TODO: finish
// if name in table.builtin_type_names {
if !known_var && (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat',
'C.sigaction'
]) {
if !known_var && (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) &&
!(name in ['C.stat', 'C.sigaction']) {
// TODO handle C.stat()
mut to_typ := p.parse_type()
if p.is_amp {
@ -1099,7 +1097,6 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
}
p.check(.key_enum)
end_pos := p.tok.position()
enum_name := p.check_name()
if enum_name.len > 0 && !enum_name[0].is_capital() {
verror('enum name `$enum_name` must begin with a capital letter')

View File

@ -162,7 +162,8 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
}
} else if p.tok.kind.is_infix() {
// return early for deref assign `*x = 2` goes to prefix expr
if p.tok.kind == .mul && p.tok.line_nr != p.prev_tok.line_nr && p.peek_tok2.kind == .assign {
if p.tok.kind == .mul && p.tok.line_nr != p.prev_tok.line_nr && p.peek_tok2.kind ==
.assign {
return node
}
// continue on infix expr

View File

@ -3,10 +3,8 @@
// that can be found in the LICENSE file.
module pref
import (
os
term
)
import os
import term
pub const (
default_module_path = mpath()
@ -22,7 +20,7 @@ pub fn new_preferences() Preferences {
return p
}
pub fn (p mut Preferences) fill_with_defaults() {
pub fn (mut p Preferences) fill_with_defaults() {
if p.vroot == '' {
// Location of all vlib files
p.vroot = os.dir(vexe_path())

View File

@ -171,16 +171,16 @@ pub const (
pub const (
integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
u16_type_idx
u32_type_idx
u16_type_idx,
u32_type_idx,
u64_type_idx
]
float_type_idxs = [f32_type_idx, f64_type_idx]
number_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
u16_type_idx
u32_type_idx
u64_type_idx
f32_type_idx
u16_type_idx,
u32_type_idx,
u64_type_idx,
f32_type_idx,
f64_type_idx
]
pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
@ -213,10 +213,10 @@ pub const (
pub const (
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64',
'u16'
'u32'
'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed'
'map', 'struct'
'u16',
'u32',
'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed',
'map', 'struct',
'mapnode', 'size_t']
)

View File

@ -17,7 +17,7 @@ fn (table &Table) has_cflag(flag cflag.CFlag) bool {
// parse the flags to (table.cflags) []CFlag
// Note: clean up big time (joe-c)
pub fn (table mut Table) parse_cflag(cflg, mod string, ctimedefines []string) ?bool {
pub fn (mut table Table) parse_cflag(cflg, mod string, ctimedefines []string) ?bool {
allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L']
flag_orig := cflg.trim_space()
mut flag := flag_orig

View File

@ -19,7 +19,7 @@ fn test_parse_valid_cflags() {
make_flag('darwin', '-framework', 'Cocoa'),
make_flag('windows', '-l', 'gdi32'),
make_flag(no_os, '-l', 'mysqlclient'),
make_flag(no_os, no_name, '-test'),
make_flag(no_os, no_name, '-test')
]
parse_valid_flag(t, '-lmysqlclient')
parse_valid_flag(t, '-test')