diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index 6747441a97..699e4b9e47 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -81,10 +81,10 @@ pub fn eprintln(s string) { panic('eprintln(NIL)') } $if !windows { - C.fflush(stdout) - C.fflush(stderr) - C.fprintf(stderr, '%.*s\n', s.len, s.str) - C.fflush(stderr) + C.fflush(C.stdout) + C.fflush(C.stderr) + C.fprintf(C.stderr, '%.*s\n', s.len, s.str) + C.fflush(C.stderr) return } // TODO issues with stderr and cross compiling for Linux @@ -96,10 +96,10 @@ pub fn eprint(s string) { panic('eprint(NIL)') } $if !windows { - C.fflush(stdout) - C.fflush(stderr) - C.fprintf(stderr, '%.*s', s.len, s.str) - C.fflush(stderr) + C.fflush(C.stdout) + C.fflush(C.stderr) + C.fprintf(C.stderr, '%.*s', s.len, s.str) + C.fflush(C.stderr) return } print(s) @@ -124,6 +124,8 @@ pub fn print(s string) { __global total_m i64=0 __global nr_mallocs int=0 +fn looo(){} // TODO remove, [ pratt + [unsafe_fn] pub fn malloc(n int) byteptr { if n <= 0 { diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index dbaee4f029..1c3cf2b9f7 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -8,12 +8,12 @@ import ( v.table ) -pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | -FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | +pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral | +FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr -pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | -ForStmt | StructDecl | ForCStmt | ForInStmt +pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt | +ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr // | IncDecStmt k // Stand-alone expression in a statement list. pub struct ExprStmt { @@ -63,7 +63,13 @@ pub struct Field { pub: name string // type_idx int - ti table.Type + typ table.Type +} + +pub struct ConstDecl { +pub: + fields []Field + exprs []Expr } pub struct StructDecl { @@ -159,6 +165,14 @@ mut: pos token.Position } +pub struct GlobalDecl { +pub: + name string + expr Expr +mut: + typ table.Type +} + pub struct File { pub: mod Module @@ -178,6 +192,7 @@ type IdentInfo = IdentVar pub enum IdentKind { blank_ident variable + constant } // A single identifier @@ -232,6 +247,7 @@ pub: // op token.Kind left Expr index Expr // [0], [start..end] etc + typ table.Type } pub struct IfExpr { @@ -242,12 +258,21 @@ pub: else_stmts []Stmt ti table.Type left Expr // `a` in `a := if ...` + pos token.Position +} + +pub struct CompIf { +pub: + cond Expr + stmts []Stmt + else_stmts []Stmt } pub struct ForStmt { pub: cond Expr stmts []Stmt + pos token.Position } pub struct ForInStmt { @@ -280,6 +305,11 @@ pub: } */ +// e.g. `[unsafe_fn]` +pub struct Attr { +pub: + name string +} pub struct AssignExpr { pub: diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c8f0319006..c640614baf 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -68,6 +68,9 @@ pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.Type { // c.error('infix expr: cannot use `$infix_expr.right_type.name` as `$infix_expr.left_type.name`', infix_expr.pos) c.error('infix expr: cannot use `$left_ti.name` as `$right_ti.name`', infix_expr.pos) } + if infix_expr.op.is_relational() { + return table.bool_type + } return left_ti } @@ -195,111 +198,120 @@ fn (c &Checker) stmt(node ast.Stmt) { ast.VarDecl { typ := c.expr(it.expr) // println('var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr') - if it.typ.kind == .unresolved { - // it.ti = typ - // println('unresolved var') - } + // if it.typ.kind == .unresolved { + // it.ti = typ + // println('unresolved var') + // } + } + ast.ForStmt { + typ := c.expr(it.cond) + if typ.kind != .bool { + c.error('non-bool used as for condition', it.pos) } - ast.ForStmt { - c.expr(it.cond) - for stmt in it.stmts { - c.stmt(stmt) - } + for stmt in it.stmts { + c.stmt(stmt) } - ast.ForCStmt { - c.stmt(it.init) - c.expr(it.cond) - c.stmt(it.inc) - for stmt in it.stmts { - c.stmt(stmt) - } + } + ast.ForCStmt { + c.stmt(it.init) + c.expr(it.cond) + c.stmt(it.inc) + for stmt in it.stmts { + c.stmt(stmt) } - // ast.StructDecl {} - ast.ExprStmt { - c.expr(it.expr) - } - else {} - } + } + // ast.StructDecl {} + ast.ExprStmt { + c.expr(it.expr) + } + else {} } +} - pub fn (c &Checker) expr(node ast.Expr) table.Type { - match node { - ast.AssignExpr { - c.check_assign_expr(it) - } - ast.IntegerLiteral { - return table.int_type - } - // ast.FloatLiteral {} - ast.PostfixExpr { - return c.expr(it.expr) - } - /* +pub fn (c &Checker) expr(node ast.Expr) table.Type { + match node { + ast.AssignExpr { + c.check_assign_expr(it) + } + ast.IntegerLiteral { + return table.int_type + } + // ast.FloatLiteral {} + ast.PostfixExpr { + return c.expr(it.expr) + } + /* ast.UnaryExpr { c.expr(it.left) } */ - ast.StringLiteral { - return table.string_type - } - ast.PrefixExpr { - return c.expr(it.right) - } - ast.InfixExpr { - return c.infix_expr(it) - } - ast.StructInit { - return c.check_struct_init(it) - } - ast.CallExpr { - return c.call_expr(it) - } - ast.MethodCallExpr { - return c.check_method_call_expr(it) - } - ast.ArrayInit { - return c.array_init(it) - } - ast.Ident { - if it.kind == .variable { - info := it.info as ast.IdentVar - if info.typ.kind != .unresolved { - return info.typ - } - return c.expr(info.expr) + ast.StringLiteral { + return table.string_type + } + ast.PrefixExpr { + return c.expr(it.right) + } + ast.InfixExpr { + return c.infix_expr(it) + } + ast.StructInit { + return c.check_struct_init(it) + } + ast.CallExpr { + return c.call_expr(it) + } + ast.MethodCallExpr { + return c.check_method_call_expr(it) + } + ast.ArrayInit { + return c.array_init(it) + } + ast.Ident { + if it.kind == .variable { + info := it.info as ast.IdentVar + if info.typ.kind != .unresolved { + return info.typ } - return table.void_type + return c.expr(info.expr) } - // ast.BoolLiteral {} - ast.SelectorExpr { - return c.selector_expr(it) + return table.void_type + } + ast.BoolLiteral { + return table.bool_type + } + ast.SelectorExpr { + return c.selector_expr(it) + } + ast.IndexExpr { + // c.expr(it.left) + // c.expr(it.index) + return it.typ + } + ast.IfExpr { + typ := c.expr(it.cond) + if typ.kind != .bool { + c.error('non-bool (`$typ.name`) used as if condition', it.pos) } - ast.IndexExpr { - c.expr(it.left) - c.expr(it.index) + for i, stmt in it.stmts { + c.stmt(stmt) } - ast.IfExpr { - c.expr(it.cond) - for i, stmt in it.stmts { + if it.else_stmts.len > 0 { + for stmt in it.else_stmts { c.stmt(stmt) } - if it.else_stmts.len > 0 { - for stmt in it.else_stmts { - c.stmt(stmt) - } - } } - else {} - } - return table.void_type + } + else {} } + return table.void_type +} - pub fn (c &Checker) error(s string, pos token.Position) { - print_backtrace() - final_msg_line := '$c.file_name:$pos.line_nr: error: $s' - eprintln(final_msg_line) - /* +pub fn (c &Checker) error(s string, pos token.Position) { + print_backtrace() + final_msg_line := '$c.file_name:$pos.line_nr: error: $s' + eprintln(final_msg_line) + /* if colored_output { eprintln(term.bold(term.red(final_msg_line))) }else{ @@ -307,5 +319,5 @@ fn (c &Checker) stmt(node ast.Stmt) { } */ - exit(1) - } + exit(1) +} diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 2267445853..4e4d5a5d42 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -51,6 +51,13 @@ fn (g mut Gen) stmt(node ast.Stmt) { // g.writeln('//// stmt start') match node { ast.Import {} + ast.ConstDecl { + for i, field in it.fields { + g.write('$field.typ.name $field.name = ') + g.expr(it.exprs[i]) + g.writeln(';') + } + } ast.FnDecl { g.fn_decl = &it is_main := it.name == 'main' @@ -145,7 +152,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.writeln('typedef struct {') for field in it.fields { // t := g.table.get_type(field.ti.idx) - ti := g.table.refresh_ti(field.ti) + ti := g.table.refresh_ti(field.typ) g.writeln('\t$ti.name $field.name;') } g.writeln('} $it.name;') diff --git a/vlib/v/gen/tests/1.c b/vlib/v/gen/tests/1.c index 783229570a..3cd4dd8dfe 100644 --- a/vlib/v/gen/tests/1.c +++ b/vlib/v/gen/tests/1.c @@ -6,6 +6,8 @@ multi_return_int_string multi_return(); void variadic(variadic_int a); void ensure_cap(int required, int cap); +int pi = 3; + typedef struct { int age; } User; @@ -19,6 +21,7 @@ int main() { a++; foo(3); int ak = 10; + int mypi = pi; return 0; } diff --git a/vlib/v/gen/tests/1.vv b/vlib/v/gen/tests/1.vv index 7446a10d17..c4bb2db3ad 100644 --- a/vlib/v/gen/tests/1.vv +++ b/vlib/v/gen/tests/1.vv @@ -1,6 +1,12 @@ import moda import modb as mb +const ( + pi = 3 + //s = 'hi' + +) + struct User { age int } @@ -15,6 +21,7 @@ fn main() { a++ foo(3) ak := 10 + mypi := pi } /* user := User{} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 0bfa875044..236c2ec97f 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -50,7 +50,7 @@ pub fn (p mut Parser) call_args() []ast.Expr { return args // ,table.void_ti } -fn (p mut Parser) fn_decl() ast.FnDecl { +fn (p mut Parser) fn_decl(/*high bool*/) ast.FnDecl { is_pub := p.tok.kind == .key_pub if is_pub { p.next() @@ -68,14 +68,18 @@ fn (p mut Parser) fn_decl() ast.FnDecl { if p.tok.kind == .key_mut { p.next() } - rec_ti = p.parse_ti() + rec_ti = p.parse_type() p.table.register_var(table.Var{ name: rec_name typ: rec_ti }) p.check(.rpar) } - name := p.check_name() + mut name := '' + if p.tok.kind == .name { + // TODO + name = p.check_name() + } // println('fn decl $name') p.check(.lpar) // Args @@ -88,7 +92,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { p.check(.comma) arg_names << p.check_name() } - ti := p.parse_ti() + ti := p.parse_type() for arg_name in arg_names { arg := table.Var{ name: arg_name @@ -112,7 +116,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { // Return type mut typ := table.void_type if p.tok.kind in [.name, .lpar] { - typ = p.parse_ti() + typ = p.parse_type() p.return_type = typ } else { @@ -144,7 +148,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { is_pub: is_pub receiver: ast.Field{ name: rec_name - ti: rec_ti + typ: rec_ti } } } diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index dbca3e2289..d5dcb64943 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -13,13 +13,13 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type { if p.tok.kind == .number { size := p.tok.lit.int() p.check(.rsbr) - elem_ti := p.parse_ti() + elem_ti := p.parse_type() idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1) return table.new_type(.array_fixed, name, idx, nr_muls) } // array p.check(.rsbr) - elem_ti := p.parse_ti() + elem_ti := p.parse_type() mut nr_dims := 1 for p.tok.kind == .lsbr { p.check(.lsbr) @@ -33,9 +33,9 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type { pub fn (p mut Parser) parse_map_ti(nr_muls int) table.Type { p.next() p.check(.lsbr) - key_ti := p.parse_ti() + key_ti := p.parse_type() p.check(.rsbr) - value_ti := p.parse_ti() + value_ti := p.parse_type() idx,name := p.table.find_or_register_map(&key_ti, &value_ti) return table.new_type(.map, name, idx, nr_muls) } @@ -44,7 +44,7 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type { p.check(.lpar) mut mr_tis := []table.Type for { - mr_ti := p.parse_ti() + mr_ti := p.parse_type() mr_tis << mr_ti if p.tok.kind == .comma { p.check(.comma) @@ -60,12 +60,18 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type { pub fn (p mut Parser) parse_variadic_ti() table.Type { p.check(.ellipsis) - variadic_ti := p.parse_ti() + variadic_ti := p.parse_type() idx,name := p.table.find_or_register_variadic(&variadic_ti) return table.new_type(.variadic, name, idx, 0) } -pub fn (p mut Parser) parse_ti() table.Type { +pub fn (p mut Parser) parse_fn_type() table.Type { + //p.check(.key_fn) + p.fn_decl() + return table.int_type +} + +pub fn (p mut Parser) parse_type() table.Type { mut nr_muls := 0 for p.tok.kind == .amp { p.check(.amp) @@ -73,6 +79,10 @@ pub fn (p mut Parser) parse_ti() table.Type { } name := p.tok.lit match p.tok.kind { + // func + .key_fn { + return p.parse_fn_type() + } // array .lsbr { return p.parse_array_ti(nr_muls) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index a9e3d84974..6e4541ef94 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -8,6 +8,7 @@ import ( v.ast v.token v.table + v.pref term os ) @@ -35,6 +36,9 @@ mut: // // prefix_parse_fns []PrefixParseFn inside_if bool + pref &pref.Preferences // Preferences shared from V struct + builtin_mod bool + mod string } // for tests @@ -59,6 +63,8 @@ pub fn parse_file(path string, table &table.Table) ast.File { scanner: scanner.new_scanner(text) table: table file_name: path + pref: &pref.Preferences{} + builtin_mod: true } p.read_first_token() // module decl @@ -170,6 +176,12 @@ pub fn (p mut Parser) top_stmt() ast.Stmt { // } } } + .lsbr { + return p.attr() + } + .key_global { + return p.global_decl() + } .key_const { return p.const_decl() } @@ -179,16 +191,12 @@ pub fn (p mut Parser) top_stmt() ast.Stmt { .key_struct { return p.struct_decl() } - .lsbr { - p.next() - p.check(.name) - p.check(.rsbr) - return ast.Module{} + .dollar { + return p.comp_if() } else { p.error('bad top level statement') - return ast.Module{} // silence C warning - // exit(0) + return ast.Stmt{} } } } @@ -204,6 +212,9 @@ pub fn (p mut Parser) stmt() ast.Stmt { .key_return { return p.return_stmt() } + .dollar { + return p.comp_if() + } else { // `x := ...` if p.tok.kind == .name && p.peek_tok.kind == .decl_assign { @@ -218,6 +229,22 @@ pub fn (p mut Parser) stmt() ast.Stmt { } } +pub fn (p mut Parser) comp_if() ast.CompIf { + p.next() + p.check(.key_if) + if p.tok.kind == .not { + p.next() + } + p.check_name() + p.parse_block() + if p.tok.kind == .dollar && p.peek_tok.kind == .key_else { + p.next() + p.check(.key_else) + p.parse_block() + } + return ast.CompIf{} +} + pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr { op := p.tok.kind p.next() @@ -231,6 +258,15 @@ pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr { return node } +fn (p mut Parser) attr() ast.Attr { + p.check(.lsbr) + name := p.check_name() + p.check(.rsbr) + return ast.Attr{ + name: name + } +} + fn (p mut Parser) range_expr(low ast.Expr) ast.Expr { // ,table.Type) { p.next() @@ -310,7 +346,8 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { mut node := ast.Expr{} // mut typ := table.void_ti mut typ := table.unresolved_type - if p.tok.lit == 'C' { + is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot + if is_c { p.next() p.check(.dot) } @@ -327,7 +364,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { } // struct init else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || p.tok.lit in ['array', 'string']) { - typ = p.parse_ti() + typ = p.parse_type() // p.warn('struct init typ=$typ.name') p.check(.lcbr) mut field_names := []string @@ -347,13 +384,13 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { } p.check(.rcbr) } - // variable else { // p.warn('name ') // left := p.parse_ident() mut ident := ast.Ident{ name: p.tok.lit } + // variable if var := p.table.find_var(p.tok.lit) { typ = var.typ ident.kind = .variable @@ -361,18 +398,40 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) { typ: typ name: ident.name // expr: p.expr(0)// var.expr - + } // ident.ti = ti node = ident p.next() }else{ - // Function object (not a call), e.g. `onclick(my_click)` - p.table.find_fn(p.tok.lit) or { - p.error('name expr unknown variable `$p.tok.lit`') - exit(0) + if is_c { + typ = table.int_type + ident.info = ast.IdentVar{ + typ: typ + name: ident.name + } + node = ident + p.next() + return node,typ + } + // const + if c := p.table.find_const(p.tok.lit) { + typ = c.typ + ident.kind = .constant + ident.info = ast.IdentVar{ + typ: typ + name: ident.name + } + node = ident + p.next() + }else{ + // Function object (not a call), e.g. `onclick(my_click)` + p.table.find_fn(p.tok.lit) or { + p.error('name expr unknown identifier `$p.tok.lit`') + exit(0) + } + p.next() } - p.next() } } return node,typ @@ -505,6 +564,7 @@ fn (p mut Parser) index_expr(left ast.Expr, typ_ table.Type) (ast.Expr,table.Typ node = ast.IndexExpr{ left: left index: index_expr + typ: typ } // return node return node,typ @@ -572,6 +632,7 @@ fn (p mut Parser) for_statement() ast.Stmt { stmts := p.parse_block() return ast.ForStmt{ stmts: stmts + pos: p.tok.position() } } else if p.tok.kind == .key_mut { @@ -600,9 +661,6 @@ fn (p mut Parser) for_statement() ast.Stmt { if p.tok.kind != .semicolon { mut typ := table.Type{} cond,typ = p.expr(0) - if typ.kind != .bool { - p.error('non-bool used as for condition') - } } p.check(.semicolon) if p.tok.kind != .lcbr { @@ -630,6 +688,7 @@ fn (p mut Parser) for_statement() ast.Stmt { // println('nr stmts=$stmts.len') return ast.ForStmt{ stmts: stmts + pos: p.tok.position() } } // `for cond {` @@ -641,6 +700,7 @@ fn (p mut Parser) for_statement() ast.Stmt { return ast.ForStmt{ cond: cond stmts: stmts + pos: p.tok.position() } } @@ -650,12 +710,8 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) { // } mut node := ast.Expr{} p.check(.key_if) - cond,cond_ti := p.expr(0) + cond,_ := p.expr(0) p.inside_if = false - // if !p.table.check(table.bool_ti, cond_ti) { - if cond_ti.kind != .bool { - p.error('non-bool (`$cond_ti.name`) used as if condition') - } stmts := p.parse_block() mut else_stmts := []ast.Stmt if p.tok.kind == .key_else { @@ -679,8 +735,9 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) { stmts: stmts else_stmts: else_stmts ti: ti + pos: p.tok.position() // left: left - + } return node,ti } @@ -708,19 +765,19 @@ fn (p mut Parser) string_expr() (ast.Expr,table.Type) { fn (p mut Parser) array_init() (ast.Expr,table.Type) { p.check(.lsbr) - mut val_ti := table.void_type + mut val_type := table.void_type mut exprs := []ast.Expr for i := 0; p.tok.kind != .rsbr; i++ { - expr,ti := p.expr(0) + expr,typ := p.expr(0) exprs << expr if i == 0 { - val_ti = ti + val_type = typ } if p.tok.kind == .comma { p.check(.comma) } } - type_idx,type_name := p.table.find_or_register_array(val_ti, 1) + type_idx,type_name := p.table.find_or_register_array(val_type, 1) array_ti := table.new_type(.array, type_name, type_idx, 0) mut node := ast.Expr{} node = ast.ArrayInit{ @@ -792,20 +849,31 @@ fn (p mut Parser) import_stmt() []ast.Import { return imports } -// TODO -// fn (p mut Parser) const_decl() ast... { -fn (p mut Parser) const_decl() ast.Stmt { +fn (p mut Parser) const_decl() ast.ConstDecl { p.check(.key_const) p.check(.lpar) + mut fields := []ast.Field + mut exprs := []ast.Expr for p.tok.kind != .rpar { name := p.check_name() println('const: $name') p.check(.assign) - _,_ := p.expr(0) - // expr, ti := p.expr(0) + expr,typ := p.expr(0) + fields << ast.Field{ + name: name + typ: typ + } + exprs << expr + p.table.register_const(table.Var{ + name: name + typ: typ + }) } p.check(.rpar) - return ast.Stmt{} + return ast.ConstDecl{ + fields: fields + exprs: exprs + } } fn (p mut Parser) struct_decl() ast.StructDecl { @@ -824,15 +892,15 @@ fn (p mut Parser) struct_decl() ast.StructDecl { p.check(.colon) } field_name := p.check_name() - ti := p.parse_ti() + ti := p.parse_type() ast_fields << ast.Field{ name: field_name - ti: ti + typ: ti } fields << table.Field{ name: field_name // type_idx: ti.idx - + ti: ti } } @@ -905,7 +973,7 @@ fn (p mut Parser) var_decl() ast.VarDecl { name: name is_mut: is_mut // expr: expr - + typ: typ }) p.warn('var decl name=$name typ=$typ.name') @@ -913,7 +981,7 @@ fn (p mut Parser) var_decl() ast.VarDecl { node := ast.VarDecl{ name: name expr: expr // p.expr(token.lowest_prec) - + is_mut: is_mut typ: typ pos: p.tok.position() @@ -921,6 +989,40 @@ fn (p mut Parser) var_decl() ast.VarDecl { return node } +fn (p mut Parser) global_decl() ast.GlobalDecl { + if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals { + p.error('use `v --enable-globals ...` to enable globals') + } + p.next() + name := p.check_name() + println(name) + typ := p.parse_type() + if p.tok.kind == .assign { + p.next() + p.expr(0) + } + p.table.register_global(name, typ) + // p.genln(p.table.cgen_name_type_pair(name, typ)) + /* + mut g := p.table.cgen_name_type_pair(name, typ) + if p.tok == .assign { + p.next() + g += ' = ' + _,expr := p.tmp_expr() + g += expr + } + // p.genln('; // global') + g += '; // global' + if !p.cgen.nogen { + p.cgen.consts << g + } + */ + + return ast.GlobalDecl{ + name: name + } +} + fn verror(s string) { println(s) exit(1) diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v new file mode 100644 index 0000000000..17658aa045 --- /dev/null +++ b/vlib/v/pref/pref.v @@ -0,0 +1,68 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module pref + +pub enum BuildMode { + // `v program.v' + // Build user code only, and add pre-compiled vlib (`cc program.o builtin.o os.o...`) + default_mode + // `v -lib ~/v/os` + // build any module (generate os.o + os.vh) + build_module +} + + +pub struct Preferences { +pub mut: + build_mode BuildMode + // nofmt bool // disable vfmt + is_test bool // `v test string_test.v` + is_script bool // single file mode (`v program.v`), main function can be skipped + is_live bool // main program that contains live/hot code + is_solive bool // a shared library, that will be used in a -live main program + is_so bool // an ordinary shared library, -shared, no matter if it is live or not + is_prof bool // benchmark every function + translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc + is_prod bool // use "-O2" + is_verbose bool // print extra information with `v.log()` + obfuscate bool // `v -obf program.v`, renames functions to "f_XXX" + is_repl bool + is_run bool + show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c + sanitize bool // use Clang's new "-fsanitize" option + is_debug bool // false by default, turned on by -g or -cg, it tells v to pass -g to the C backend compiler. + is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly). + is_keep_c bool // -keep_c , tell v to leave the generated .tmp.c alone (since by default v will delete them after c backend finishes) + // NB: passing -cg instead of -g will set is_vlines to false and is_g to true, thus making v generate cleaner C files, + // which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks). + is_pretty_c bool // -pretty_c , tell v to run clang-format -i over the produced C file, before it is compiled. Use with -keep_c or with -o x.c . + is_cache bool // turns on v usage of the module cache to speed up compilation. + is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run + no_auto_free bool // `v -nofree` disable automatic `free()` insertion for better performance in some applications (e.g. compilers) + cflags string // Additional options which will be passed to the C compiler. + // For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size. + // You could pass several -cflags XXX arguments. They will be merged with each other. + // You can also quote several options at the same time: -cflags '-Os -fno-inline-small-functions'. + ccompiler string // the name of the used C compiler + building_v bool + autofree bool + compress bool + // skip_builtin bool // Skips re-compilation of the builtin module + // to increase compilation time. + // This is on by default, since a vast majority of users do not + // work on the builtin module itself. + // generating_vh bool + fast bool // use tcc/x64 codegen + enable_globals bool // allow __global for low level code + // is_fmt bool + is_bare bool + user_mod_path string // `v -user_mod_path /Users/user/modules` adds a new lookup path for imported modules + vlib_path string + vpath string + x64 bool + output_cross_c bool + prealloc bool + v2 bool +} + diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index aedc759eb4..c36f28692d 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -14,6 +14,7 @@ pub mut: local_vars []Var // fns Hashmap fns map[string]Fn + consts map[string]Var tmp_cnt int imports []string } @@ -27,11 +28,13 @@ pub: pub struct Var { pub: - name string - is_mut bool + name string + is_mut bool + is_const bool + is_global bool // expr ast.Expr mut: - typ Type + typ Type } pub fn new_table() &Table { @@ -78,6 +81,23 @@ pub fn (t mut Table) clear_vars() { } } +pub fn (t mut Table) register_const(v Var) { + t.consts[v.name] = v +} + +pub fn (t mut Table) register_global(name string, typ Type) { + t.consts[name] = Var{ + name: name + typ: typ + is_const: true + is_global: true + // mod: p.mod + // is_mut: true + // idx: -1 + + } +} + pub fn (t mut Table) register_var(v Var) { println('register_var: $v.name - $v.typ.name') t.local_vars << v @@ -112,6 +132,15 @@ pub fn (t &Table) find_fn(name string) ?Fn { return none } +pub fn (t &Table) find_const(name string) ?Var { + f := t.consts[name] + if f.name.str != 0 { + // TODO + return f + } + return none +} + pub fn (t mut Table) register_fn(new_fn Fn) { // println('reg fn $new_fn.name nr_args=$new_fn.args.len') t.fns[new_fn.name] = new_fn @@ -351,7 +380,7 @@ pub fn (t &Table) check(got, expected &Type) bool { // if expected.name == 'array' { // return true // } - if got.idx != expected.idx { + if got.idx != expected.idx && got.name != expected.name { return false } return true