From 011e26ca9a0dd54c17af2cb09769fc8c5b9c892d Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 21 Jun 2020 23:09:17 +0200 Subject: [PATCH] checker: check sum types in `match`; cross compilation fixes; orm fixes --- cmd/tools/vfmt.v | 2 +- vlib/sqlite/sqlite.v | 4 ++++ vlib/v/ast/ast.v | 39 ++++++++++++++++---------------- vlib/v/builder/cc.v | 32 ++++++++++++++++---------- vlib/v/checker/checker.v | 19 +++++++++++----- vlib/v/gen/js/js.v | 3 --- vlib/v/gen/sql.v | 8 +++++-- vlib/v/parser/comptime.v | 49 ++++++++++++++++++++++++++-------------- vlib/v/parser/if.v | 3 ++- vlib/v/parser/parser.v | 8 +++++-- vlib/v/parser/pratt.v | 2 ++ vlib/v/parser/sql.v | 28 ++++++++--------------- 12 files changed, 116 insertions(+), 81 deletions(-) diff --git a/cmd/tools/vfmt.v b/cmd/tools/vfmt.v index af6b95c289..453b892e43 100644 --- a/cmd/tools/vfmt.v +++ b/cmd/tools/vfmt.v @@ -44,7 +44,7 @@ fn main() { foptions := FormatOptions{ is_c: '-c' in args is_l: '-l' in args - is_w: '-w' in args + is_w: '-ww' in args is_diff: '-diff' in args is_verbose: '-verbose' in args || '--verbose' in args is_all: '-all' in args || '--all' in args diff --git a/vlib/sqlite/sqlite.v b/vlib/sqlite/sqlite.v index 53697f237a..faf3bec7cc 100644 --- a/vlib/sqlite/sqlite.v +++ b/vlib/sqlite/sqlite.v @@ -3,6 +3,10 @@ module sqlite #flag -lsqlite3 #flag freebsd -I/usr/local/include #flag freebsd -Wl -L/usr/local/lib -lsqlite3 +//#flag linux -I @VROOT/thirdparty/sqlite +//#flag @VROOT/thirdparty/sqlite/sqlite.c + + #include "sqlite3.h" struct C.sqlite3 {} diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 152928ef27..4d11a11091 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -9,16 +9,16 @@ import v.errors pub type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl -pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr | CharLiteral | - ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr | IndexExpr | - InfixExpr | IntegerLiteral | Likely | MapInit | MatchExpr | None | OrExpr | ParExpr | PostfixExpr | - PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | - StructInit | Type | TypeOf +pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | CastExpr | + CharLiteral | ComptimeCall | ConcatExpr | EnumVal | FloatLiteral | Ident | IfExpr | IfGuardExpr | + IndexExpr | InfixExpr | IntegerLiteral | Likely | MapInit | MatchExpr | None | OrExpr | + ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | + StringLiteral | StructInit | Type | TypeOf -pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | ConstDecl | - DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | GoStmt | - GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | SqlInsertExpr | - StructDecl | TypeDecl | UnsafeStmt +pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | + ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | + GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | + Return | SqlInsertExpr | StructDecl | TypeDecl | UnsafeStmt pub type ScopeObject = ConstField | GlobalDecl | Var @@ -809,7 +809,7 @@ pub enum SqlExprKind { */ pub struct SqlInsertExpr { pub: - db_var_name string // `db` in `sql db {` + db_expr Expr // `db` in `sql db {` table_name string object_var_name string // `user` table_type table.Type @@ -817,14 +817,14 @@ pub: pub struct SqlExpr { pub: - typ table.Type - is_count bool - db_var_name string // `db` in `sql db {` - table_name string - where_expr Expr - has_where bool - fields []table.Field - is_array bool + typ table.Type + is_count bool + db_expr Expr // `db` in `sql db {` + table_name string + where_expr Expr + has_where bool + fields []table.Field + is_array bool } [inline] @@ -879,7 +879,8 @@ pub fn (expr Expr) position() token.Position { InfixExpr { left_pos := expr.left.position() right_pos := expr.right.position() - if left_pos.pos == 0 || right_pos.pos == 0 { + if left_pos.pos == 0 || + right_pos.pos == 0 { return expr.pos } return token.Position{ diff --git a/vlib/v/builder/cc.v b/vlib/v/builder/cc.v index d3e014a795..1613bb32a2 100644 --- a/vlib/v/builder/cc.v +++ b/vlib/v/builder/cc.v @@ -391,6 +391,10 @@ fn (mut v Builder) cc() { linker_flags << '-lm' } args := a.join(' ') + ' ' + linker_flags.join(' ') + if v.pref.is_verbose { + println('cc args=$args') + println(a) + } start: todo() // TODO remove @@ -512,7 +516,7 @@ fn (mut v Builder) cc() { } } -fn (mut c Builder) cc_linux_cross() { +fn (mut b Builder) cc_linux_cross() { parent_dir := os.home_dir() + '.vmodules' sysroot := os.home_dir() + '.vmodules/linuxroot/' if !os.is_dir(sysroot) { @@ -526,17 +530,22 @@ fn (mut c Builder) cc_linux_cross() { } } - mut cc_args := '-fPIC -w -c -target x86_64-linux-gnu -c -o x.o $c.out_name_c -I $sysroot/include' - if c.pref.show_cc { + mut cc_args := '-fPIC -w -c -target x86_64-linux-gnu -c -o x.o $b.out_name_c -I $sysroot/include ' + cflags := b.get_os_cflags() + cc_args += cflags.c_options_without_object_files() + if b.pref.show_cc { println('cc $cc_args') } - if os.system('cc $cc_args') != 0 { - println('Cross compilation for Linux failed. Make sure you have clang installed.') + cc_res := os.exec('cc $cc_args') or { return } + if cc_res.exit_code != 0 { + println('Cross compilation for Linux failed (first step, clang). Make sure you have clang installed.') + println(cc_res.output) + exit(1) } linker_args := [ '-L $sysroot/usr/lib/x86_64-linux-gnu/' - '--sysroot=$sysroot -v -o $c.pref.out_name -m elf_x86_64' + '--sysroot=$sysroot -v -o $b.pref.out_name -m elf_x86_64' '-dynamic-linker /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2' '$sysroot/crt1.o $sysroot/crti.o x.o' //'SYSROOT/lib/x86_64-linux-gnu/libc.so.6' @@ -554,17 +563,16 @@ fn (mut c Builder) cc_linux_cross() { cmd := '$sysroot/ld.lld ' + linker_args_str //s = s.replace('SYSROOT', sysroot) // TODO $ inter bug //s = s.replace('-o hi', '-o ' + c.pref.out_name) - if c.pref.show_cc { + if b.pref.show_cc { println(cmd) } res := os.exec(cmd) or { return } - //println('output:') - //println(x.output) if res.exit_code != 0 { - println('Cross compilation for Linux failed. Make sure you have clang installed.') - return + println('Cross compilation for Linux failed (second step, lld):') + println(res.output) + exit(1) } - println(c.pref.out_name + ' has been successfully compiled') + println(b.pref.out_name + ' has been successfully compiled') } fn (mut c Builder) cc_windows_cross() { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 04115ededb..9973aac9f7 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -143,11 +143,14 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool { c.warn('const $no_pub_in_main_warning', stmt.pos) } } + /* + // TODO not a Stmt ast.ConstField { if stmt.is_pub { c.warn('const field `$stmt.name` $no_pub_in_main_warning', stmt.pos) } } + */ ast.EnumDecl { if stmt.is_pub { c.warn('enum `$stmt.name` $no_pub_in_main_warning', stmt.pos) @@ -1206,7 +1209,6 @@ pub fn (mut c Checker) selector_expr(mut selector_expr ast.SelectorExpr) table.T return table.void_type } selector_expr.expr_type = typ - // println('sel expr line_nr=$selector_expr.pos.line_nr typ=$selector_expr.expr_type') sym := c.table.get_type_symbol(c.unwrap_generic(typ)) field_name := selector_expr.field_name // variadic @@ -1795,6 +1797,9 @@ fn (mut c Checker) stmt(node ast.Stmt) { c.return_stmt(mut it) c.scope_returns = true } + ast.SqlInsertExpr { + c.sql_insert_expr(node) + } ast.StructDecl { c.struct_decl(it) } @@ -1932,7 +1937,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { if node.is_vweb { // TODO assoc parser bug pref := *c.pref - pref2 := {pref|is_vweb: true} + pref2 := {pref|is_vweb: true} mut c2 := new_checker(c.table, pref2) c2.check(node.vweb_tmpl) c.warnings << c2.warnings @@ -2023,9 +2028,6 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { ast.SqlExpr { return c.sql_expr(node) } - ast.SqlInsertExpr { - return c.sql_insert_expr(node) - } ast.StringLiteral { if node.language == .c { return table.byteptr_type @@ -2225,8 +2227,11 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type { if node.is_sum_type || node.is_interface { ok := if cond_type_sym.kind == .sum_type { // TODO verify sum type - true // c.check_types(typ, cond_type) + //true // c.check_types(typ, cond_type) + info := cond_type_sym.info as table.SumType + typ in info.variants } else { + // interface match c.type_implements(typ, cond_type, node.pos) } if !ok { @@ -2625,10 +2630,12 @@ fn (mut c Checker) sql_expr(node ast.SqlExpr) table.Type { if node.has_where { c.expr(node.where_expr) } + c.expr(node.db_expr) return node.typ } fn (mut c Checker) sql_insert_expr(node ast.SqlInsertExpr) table.Type { + c.expr(node.db_expr) return table.void_type } diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 19e8a655bc..9f63c191fc 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -601,9 +601,6 @@ fn (mut g JsGen) expr(node ast.Expr) { ast.SqlExpr{ // TODO } - ast.SqlInsertExpr{ - // TODO - } ast.StringInterLiteral { g.gen_string_inter_literal(it) } diff --git a/vlib/v/gen/sql.v b/vlib/v/gen/sql.v index ec29f99ed5..d34ec6312c 100644 --- a/vlib/v/gen/sql.v +++ b/vlib/v/gen/sql.v @@ -20,7 +20,9 @@ fn (mut g Gen) sql_insert_expr(node ast.SqlInsertExpr) { g.writeln('\n\t// sql insert') db_name := g.new_tmp_var() g.sql_stmt_name = g.new_tmp_var() - g.writeln('${dbtype}__DB $db_name = $node.db_var_name;') + g.write('${dbtype}__DB $db_name = ') + g.expr(node.db_expr) + g.writeln(';') mut q := 'insert into $node.table_name (' for i, field in fields { if field.name == 'id' { @@ -95,7 +97,9 @@ fn (mut g Gen) sql_select_expr(node ast.SqlExpr) { db_name := g.new_tmp_var() g.writeln('\n\t// sql select') // g.write('${dbtype}__DB $db_name = *(${dbtype}__DB*)${node.db_var_name}.data;') - g.writeln('${dbtype}__DB $db_name = $node.db_var_name;') + g.write('${dbtype}__DB $db_name = ') // $node.db_var_name;') + g.expr(node.db_expr) + g.writeln(';') // g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt(*(${dbtype}__DB*)${node.db_var_name}.data, tos_lit("$q') g.write('sqlite3_stmt* $g.sql_stmt_name = ${dbtype}__DB_init_stmt($db_name, tos_lit("$q') if node.has_where && node.where_expr is ast.InfixExpr { diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index fe494923fc..e47caca449 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -10,8 +10,9 @@ import v.vmod import v.table import vweb.tmpl +// #flag darwin -I. const ( - supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', + supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', 'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos'] supported_ccompilers = ['tinyc', 'clang', 'mingw', 'msvc', 'gcc'] ) @@ -21,7 +22,7 @@ fn (mut p Parser) resolve_vroot(flag string) string { vmod_file_location := mcache.get_by_folder(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.') } vmod_path := vmod_file_location.vmod_folder @@ -56,7 +57,7 @@ fn (mut p Parser) hash() ast.HashStmt { } for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] { if flag.contains(deprecated) { - p.error('${deprecated} had been deprecated, use @VROOT instead.') + p.error('$deprecated had been deprecated, use @VROOT instead.') } } // println('adding flag "$flag"') @@ -110,7 +111,7 @@ fn (mut p Parser) vweb() ast.ComptimeCall { mut file := parse_text(v_code, p.table, p.pref, scope, p.global_scope) if p.pref.is_verbose { println('\n\n') - println('>>> vweb template for ${path}:') + println('>>> vweb template for $path:') println(v_code) println('>>> end of vweb template END') println('\n\n') @@ -156,20 +157,20 @@ fn (mut p Parser) comp_if() ast.Stmt { val := p.check_name() mut stmts := []ast.Stmt{} mut skip := false - if val in supported_platforms { os := os_from_string(val) - if (!is_not && os != p.pref.os) || (is_not && os == p.pref.os) { + if (!is_not && os != p.pref.os) || + (is_not && os == p.pref.os) { skip = true } } else if val in supported_ccompilers { cc := cc_from_string(val) user_cc := cc_from_string(p.pref.ccompiler) - if (!is_not && cc != user_cc) || (is_not && cc == user_cc) { + if (!is_not && cc != user_cc) || + (is_not && cc == user_cc) { skip = true } } - // `$if os {` or `$if compiler {` for a different target, skip everything inside // to avoid compilation errors (like including or calling WinAPI fns // on non-Windows systems) @@ -196,8 +197,9 @@ fn (mut p Parser) comp_if() ast.Stmt { } p.next() } - } else { skip = false } - + } else { + skip = false + } mut is_opt := false if p.tok.kind == .question { p.next() @@ -213,7 +215,8 @@ fn (mut p Parser) comp_if() ast.Stmt { val: val stmts: stmts } - if p.tok.kind == .dollar && p.peek_tok.kind == .key_else { + if p.tok.kind == .dollar && + p.peek_tok.kind == .key_else { p.next() p.next() node.has_else = true @@ -282,13 +285,25 @@ fn os_from_string(os string) pref.OS { // Helper function to convert string names to CC enum pub fn cc_from_string(cc_str string) pref.CompilerType { - if cc_str.len == 0 { return .gcc } + if cc_str.len == 0 { + return .gcc + } cc := cc_str.replace('\\', '/').split('/').last().all_before('.') - if 'tcc' in cc { return .tinyc } - if 'tinyc' in cc { return .tinyc } - if 'clang' in cc { return .clang } - if 'mingw' in cc { return .mingw } - if 'msvc' in cc { return .msvc } + if 'tcc' in cc { + return .tinyc + } + if 'tinyc' in cc { + return .tinyc + } + if 'clang' in cc { + return .clang + } + if 'mingw' in cc { + return .mingw + } + if 'msvc' in cc { + return .msvc + } return .gcc } diff --git a/vlib/v/parser/if.v b/vlib/v/parser/if.v index a1ca04c6cf..ceee463488 100644 --- a/vlib/v/parser/if.v +++ b/vlib/v/parser/if.v @@ -161,7 +161,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr { p.parse_type() } is_sum_type = true - + } else { // Expression match for { @@ -204,6 +204,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr { len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len } p.check(.rcbr) + //return ast.StructInit{} return ast.MatchExpr{ branches: branches cond: cond diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 42308f2724..dbd50af7fb 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -333,7 +333,11 @@ fn (mut p Parser) check(expected token.Kind) { // p.next() // } if p.tok.kind != expected { - p.error('unexpected `$p.tok.kind.str()`, expecting `$expected.str()`') + if p.tok.kind == .name { + p.error('unexpected name `$p.tok.lit`, expecting `$expected.str()`') + } else { + p.error('unexpected `$p.tok.kind.str()`, expecting `$expected.str()`') + } } p.next() } @@ -907,7 +911,7 @@ pub fn (mut p Parser) name_expr() ast.Expr { node = p.call_expr(language, mod) } } else if p.peek_tok.kind == .lcbr && !p.inside_match && !p.inside_match_case && !p.inside_if && - !p.inside_for { + !p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) { return p.struct_init(false) // short_syntax: false } else if p.peek_tok.kind == .dot && (p.tok.lit[0].is_capital() && !known_var && language == .v) { diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v index 457d6e70c4..f0e73bd60e 100644 --- a/vlib/v/parser/pratt.v +++ b/vlib/v/parser/pratt.v @@ -21,7 +21,9 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { } .name { if p.tok.lit == 'sql' && p.peek_tok.kind == .name { + p.inside_match = true // reuse the same var for perf instead of inside_sql TODO rename node = p.sql_expr() + p.inside_match = false } else { node = p.name_expr() p.is_stmt_ident = is_stmt_ident diff --git a/vlib/v/parser/sql.v b/vlib/v/parser/sql.v index c973b3241e..1316b2ef00 100644 --- a/vlib/v/parser/sql.v +++ b/vlib/v/parser/sql.v @@ -9,7 +9,7 @@ import v.table fn (mut p Parser) sql_expr() ast.Expr { // `sql db {` p.check_name() - db_var_name := p.check_name() + db_expr := p.expr(0) p.check(.lcbr) // kind := ast.SqlExprKind.select_ // @@ -31,7 +31,8 @@ fn (mut p Parser) sql_expr() ast.Expr { sym := p.table.get_type_symbol(table_type) table_name := sym.name mut where_expr := ast.Expr{} - has_where := p.tok.kind == .name && p.tok.lit == 'where' + has_where := p.tok.kind == .name && + p.tok.lit == 'where' mut query_one := false // one object is returned, not an array if has_where { p.next() @@ -63,19 +64,7 @@ fn (mut p Parser) sql_expr() ast.Expr { // get only string and int fields // mut fields := []Var info := sym.info as table.Struct - fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type]) - /* - for i, field in info.fields { - if !(field.typ in ['string', 'int', 'bool']) { - println('orm: skipping $field.name') - continue - } - if field.attr.contains('skip') { - continue - } - fields << field -} - */ + fields := info.fields.filter(it.typ in [table.string_type, table.int_type, table.bool_type] && 'skip' !in it.attrs) if fields.len == 0 { p.error('V orm: select: empty fields in `$table_name`') } @@ -96,7 +85,7 @@ fn (mut p Parser) sql_expr() ast.Expr { return ast.SqlExpr{ is_count: is_count typ: typ - db_var_name: db_var_name + db_expr: db_expr table_name: table_name where_expr: where_expr has_where: has_where @@ -106,9 +95,12 @@ fn (mut p Parser) sql_expr() ast.Expr { } fn (mut p Parser) sql_insert_expr() ast.SqlInsertExpr { + p.inside_match = true + defer { p.inside_match = false } // `sql db {` p.check_name() - db_var_name := p.check_name() + db_expr := p.expr(0) + //println(typeof(db_expr)) p.check(.lcbr) // kind := ast.SqlExprKind.select_ // @@ -130,7 +122,7 @@ fn (mut p Parser) sql_insert_expr() ast.SqlInsertExpr { table_name := sym.name p.check(.rcbr) return ast.SqlInsertExpr{ - db_var_name: db_var_name + db_expr: db_expr table_name: table_name table_type: table_type object_var_name: object_var_name