From bf1ee28194a9619f11d8d47bab6c9fc6dbab8850 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sat, 21 Sep 2019 21:38:12 +0300 Subject: [PATCH] ui: Objective-C @interface support for Cocoa; minor clean-ups --- compiler/fn.v | 14 +----- compiler/gen_c.v | 20 ++++---- compiler/parser.v | 64 +++++++------------------ compiler/table.v | 6 +++ examples/hot_reload/graph.v | 2 +- examples/hot_reload/message.v | 8 ++-- september.plan | 4 +- vlib/darwin/darwin.v | 2 +- vlib/os/os.v | 3 +- vlib/ui/examples/users_gui/users.v | 76 ++++++++++++++++++++++++++---- vlib/ui/ui_mac.v | 2 - 11 files changed, 112 insertions(+), 89 deletions(-) diff --git a/compiler/fn.v b/compiler/fn.v index 1050b2c9b9..22f7b79dfb 100644 --- a/compiler/fn.v +++ b/compiler/fn.v @@ -63,16 +63,6 @@ fn (p &Parser) find_var_check_new_var(name string) ?Var { return none } -fn (f &Fn) find_var2(name string) Var { - for i in 0 .. f.var_idx { - if f.local_vars[i].name == name { - return f.local_vars[i] - } - } - return Var{} -} - - fn (p mut Parser) open_scope() { p.cur_fn.defer_text << '' p.cur_fn.scope_level++ @@ -736,7 +726,7 @@ fn (p mut Parser) fn_args(f mut Fn) { is_arg: true // is_mut: is_mut line_nr: p.scanner.line_nr - scanner_pos: p.scanner.get_scanner_pos() + scanner_pos: p.scanner.get_scanner_pos() } // f.register_var(v) f.args << v @@ -781,7 +771,7 @@ fn (p mut Parser) fn_args(f mut Fn) { is_mut: is_mut ptr: is_mut line_nr: p.scanner.line_nr - scanner_pos: p.scanner.get_scanner_pos() + scanner_pos: p.scanner.get_scanner_pos() } f.register_var(v) f.args << v diff --git a/compiler/gen_c.v b/compiler/gen_c.v index c00260218a..0a97577912 100644 --- a/compiler/gen_c.v +++ b/compiler/gen_c.v @@ -71,26 +71,28 @@ fn (p mut Parser) gen_fn_decl(f Fn, typ, str_args string) { fn types_to_c(types []Type, table &Table) string { mut sb := strings.new_builder(10) for t in types { - if t.cat != .union_ && t.cat != .struct_ { + if t.cat != .union_ && t.cat != .struct_ && t.cat != .objc_interface { continue } - //if is_objc { - //sb.writeln('@interface $name : $objc_parent { @public') - //} //if is_atomic { //sb.write('_Atomic ') //} - kind := if t.cat == .union_ {'union'} else {'struct'} - sb.writeln('$kind $t.name {') + if t.cat == .objc_interface { + sb.writeln('@interface $t.name : $t.parent { @public') + } + else { + kind := if t.cat == .union_ {'union'} else {'struct'} + sb.writeln('$kind $t.name {') + } for field in t.fields { sb.write('\t') sb.writeln(table.cgen_name_type_pair(field.name, field.typ) + ';') } sb.writeln('};\n') - //if is_objc { - //sb.writeln('@end') - //} + if t.cat == .objc_interface { + sb.writeln('@end') + } } return sb.str() } diff --git a/compiler/parser.v b/compiler/parser.v index 7609327510..c702e8a6ff 100644 --- a/compiler/parser.v +++ b/compiler/parser.v @@ -492,14 +492,17 @@ fn key_to_type_cat(tok Token) TypeCategory { // also unions and interfaces fn (p mut Parser) struct_decl() { // V can generate Objective C for integration with Cocoa - // `[interface:ParentInterface]` - //is_objc := p.attr.starts_with('interface') - //objc_parent := if is_objc { p.attr.right(10) } else { '' } + // `[objc_interface:ParentInterface]` + is_objc := p.attr.starts_with('objc_interface') + objc_parent := if is_objc { p.attr.right(15) } else { '' } // interface, union, struct is_interface := p.tok == .key_interface is_union := p.tok == .key_union is_struct := p.tok == .key_struct mut cat := key_to_type_cat(p.tok) + if is_objc { + cat = .objc_interface + } p.fgen(p.tok.str() + ' ') // Get type name p.next() @@ -530,7 +533,11 @@ fn (p mut Parser) struct_decl() { if p.pass == .decl && p.table.known_type_fast(typ) { p.error('`$name` redeclared') } - if !is_c { + if is_objc { + // Forward declaration of an Objective-C interface with `@class` :) + p.gen_typedef('@class $name;') + } + else if !is_c { kind := if is_union {'union'} else {'struct'} p.gen_typedef('typedef $kind $name $name;') } @@ -544,6 +551,7 @@ fn (p mut Parser) struct_decl() { typ.is_c = is_c typ.is_placeholder = false typ.cat = cat + typ.parent = objc_parent p.table.rewrite_type(typ) } else { @@ -552,6 +560,7 @@ fn (p mut Parser) struct_decl() { mod: p.mod is_c: is_c cat: cat + parent: objc_parent } } // Struct `C.Foo` declaration, no body @@ -1715,12 +1724,6 @@ fn (p mut Parser) name_expr() string { p.error('undefined: `$name`') } else { - if orig_name == 'i32' { - println('`i32` alias was removed, use `int` instead') - } - if orig_name == 'u8' { - println('`u8` alias was removed, use `byte` instead') - } p.error('undefined: `$orig_name`') } } else { @@ -2852,42 +2855,11 @@ fn (p mut Parser) array_init() string { } fn (p mut Parser) struct_init(typ string) string { - //p.gen('/* struct init */') p.is_struct_init = true t := p.table.find_type(typ) if p.gen_struct_init(typ, t) { return typ } p.scanner.fmt_out.cut(typ.len) ptr := typ.contains('*') - /* - if !ptr { - if p.is_c_struct_init { - // `face := C.FT_Face{}` => `FT_Face face;` - if p.tok == .rcbr { - p.is_empty_c_struct_init = true - p.check(.rcbr) - return typ - } - p.gen('(struct $typ) {') - p.is_c_struct_init = false - } - else { - p.gen('($typ /*str init */) {') - } - } - else { - // TODO tmp hack for 0 pointers init - // &User{!} ==> 0 - if p.tok == .not { - p.next() - p.gen('0') - p.check(.rcbr) - return typ - } - p.is_alloc = true - //println('setting is_alloc=true (ret $typ)') - p.gen('($t.name*)memdup(&($t.name) {') - } - */ mut did_gen_something := false // Loop thru all struct init keys and assign values // u := User{age:20, name:'bob'} @@ -3763,13 +3735,11 @@ fn (p mut Parser) js_decode() string { fn (p mut Parser) attribute() { p.check(.lsbr) - if p.tok == .key_interface { - p.check(.key_interface) + p.attr = p.check_name() + if p.tok == .colon { p.check(.colon) - p.attr = 'interface:' + p.check_name() - } else { - p.attr = p.check_name() - } + p.attr = p.attr + ':' + p.check_name() + } p.check(.rsbr) if p.tok == .func || (p.tok == .key_pub && p.peek() == .func) { p.fn_decl() diff --git a/compiler/table.v b/compiler/table.v index 3ceee1aca9..6c755bc685 100644 --- a/compiler/table.v +++ b/compiler/table.v @@ -54,6 +54,7 @@ enum TypeCategory { union_ // 5 c_struct c_typedef + objc_interface // 8 Objective C @interface array } @@ -607,6 +608,11 @@ fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool { // if expected == 'T' || expected.contains('') { // return true // } + // TODO fn hack + if got.starts_with('fn ') && (expected.ends_with('fn') || + expected.ends_with('Fn')) { + return true + } // Allow pointer arithmetic if expected=='void*' && got=='int' { return true diff --git a/examples/hot_reload/graph.v b/examples/hot_reload/graph.v index b9b6f3a65d..38f56d3a29 100644 --- a/examples/hot_reload/graph.v +++ b/examples/hot_reload/graph.v @@ -42,7 +42,7 @@ fn (ctx &Context) draw() { ctx.gg.draw_line(Size / 2, 0, Size / 2, Size) // y axis center := f64(Size / 2) for x := -10.0; x <= 10.0; x += 0.002 { - y := x * x + 1 + y := x * x - 1 //y := (x + 3) * (x + 3) - 1 //y := math.sqrt(30.0 - x * x) ctx.gg.draw_rect(center + x * Scale, center - y * Scale, 1, 1, gx.Black) diff --git a/examples/hot_reload/message.v b/examples/hot_reload/message.v index 9822d91bcc..0c88cc65e1 100644 --- a/examples/hot_reload/message.v +++ b/examples/hot_reload/message.v @@ -1,18 +1,18 @@ // Build this example with -// v -live message.v +// v -live message.v module main import time -[live] +[live] fn print_message() { - println('Hello! Modify this message while the program is running.') + println('Hello! Modify this message while the program is running.') } fn main() { for { print_message() - time.sleep_ms(500) + time.sleep_ms(500) } } diff --git a/september.plan b/september.plan index b04d7e3d88..5989b7cd6f 100644 --- a/september.plan +++ b/september.plan @@ -32,6 +32,6 @@ + o(log n) type lookup - prebuilt binaries for all platforms - fix interfaces -- `none` keyword for optionals -- table: migrate all find*** functions to optionals ++ `none` keyword for optionals ++ table: migrate all find*** functions to optionals diff --git a/vlib/darwin/darwin.v b/vlib/darwin/darwin.v index f820ce57d3..5b79ca7dc6 100644 --- a/vlib/darwin/darwin.v +++ b/vlib/darwin/darwin.v @@ -6,7 +6,7 @@ module darwin struct C.NSString { } // macOS and iOS helpers -fn nsstring(s string) *NSString { +pub fn nsstring(s string) *NSString { // #return @"" ; // println('ns $s len=$s.len') # return [ [ NSString alloc ] initWithBytesNoCopy:s.str length:s.len diff --git a/vlib/os/os.v b/vlib/os/os.v index 57ab1f60cc..05e19be6cb 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -771,7 +771,8 @@ pub fn file_last_mod_unix(path string) int { } -fn log(s string) { +pub fn log(s string) { + println('os.log: ' + s) } pub fn flush_stdout() { diff --git a/vlib/ui/examples/users_gui/users.v b/vlib/ui/examples/users_gui/users.v index a50b22da49..ef428fc6c1 100644 --- a/vlib/ui/examples/users_gui/users.v +++ b/vlib/ui/examples/users_gui/users.v @@ -15,6 +15,7 @@ struct User { } struct Context { + mut: first_name ui.TextBox last_name ui.TextBox age ui.TextBox @@ -23,6 +24,61 @@ struct Context { txt_pos int } +/* +struct Window { + width: 500 + height: 300 + title: 'Users' + content: Layout { + [ + TextBox { + placeholder: 'First name' + }, + TextBox { + placeholder: 'Last name' + }, + TextBox { + placeholder: 'Age' + }, + Button { + title: 'Add user' + onclick: btn_click + }, + ] + } + + draw: { + + } +} + +/* + +Window { + width: 500 + height: 300 + title: 'Users' + VLayout { + TextBox { + placeholder: 'First name' + } + TextBox { + placeholder: 'Last name' + } + TextBox { + placeholder: 'Age' + } + Button { + title: 'Add user' + onclick: btn_click + } + } + + draw: draw_fn +} +*/ +*/ + fn main() { mut ctx := &Context { txt_pos: 10 @@ -45,30 +101,30 @@ fn main() { } // TODO replace with `fn (ctx mut Context) btn_click() {` -fn btn_click(_ctx *Context) { - mut ctx = _ctx// TODO hack +fn btn_click(_ctx &Context) { + mut ctx := _ctx// TODO hack ctx.users << User { first_name: ctx.first_name.text() last_name: ctx.last_name.text() - age: ctx.age.text().to_i() + age: ctx.age.text().int() } ctx.window.refresh() } // TODO replace with `fn (ctx mut Context) draw() {` -fn draw(ctx *Context) { +fn draw(ctx &Context) { for i, user in ctx.users { x := 10 y := 10 + i * CELL_HEIGHT // Outer border - gx.draw_empty_rect(x, y, TABLE_WIDTH, CELL_HEIGHT, gx.GRAY) + ui.draw_empty_rect(x, y, TABLE_WIDTH, CELL_HEIGHT, gx.Gray) // Vertical separators - gx.draw_line(x + CELL_WIDTH, y, x + CELL_WIDTH, y + CELL_HEIGHT) - gx.draw_line(x + CELL_WIDTH * 2, y, x + CELL_WIDTH * 2, y + CELL_HEIGHT) + ui.draw_line(x + CELL_WIDTH, y, x + CELL_WIDTH, y + CELL_HEIGHT, gx.Gray) + ui.draw_line(x + CELL_WIDTH * 2, y, x + CELL_WIDTH * 2, y + CELL_HEIGHT, gx.Gray) // Text values - gx.draw_text_def(x + 5, y + 5, user.first_name) - gx.draw_text_def(x + 5 + CELL_WIDTH, y + 5, user.last_name) - gx.draw_text_def(x + 5 + CELL_WIDTH * 2, y + 5, user.age.str()) + ui.draw_text_def(x + 5, y + 5, user.first_name) + ui.draw_text_def(x + 5 + CELL_WIDTH, y + 5, user.last_name) + ui.draw_text_def(x + 5 + CELL_WIDTH * 2, y + 5, user.age.str()) } } diff --git a/vlib/ui/ui_mac.v b/vlib/ui/ui_mac.v index c1b112f289..7496e21980 100644 --- a/vlib/ui/ui_mac.v +++ b/vlib/ui/ui_mac.v @@ -28,5 +28,3 @@ pub fn reg_key_vid() { #RegisterEventHotKey(kVK_ANSI_1, cmdKey, gMyHotKeyID, #GetApplicationEventTarget(), 0, &gMyHotKeyRef); } - -