ui: Objective-C @interface support for Cocoa; minor clean-ups

pull/2086/head
Alexander Medvednikov 2019-09-21 21:38:12 +03:00
parent fbc19311b5
commit bf1ee28194
11 changed files with 112 additions and 89 deletions

View File

@ -63,16 +63,6 @@ fn (p &Parser) find_var_check_new_var(name string) ?Var {
return none 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() { fn (p mut Parser) open_scope() {
p.cur_fn.defer_text << '' p.cur_fn.defer_text << ''
p.cur_fn.scope_level++ p.cur_fn.scope_level++
@ -736,7 +726,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
is_arg: true is_arg: true
// is_mut: is_mut // is_mut: is_mut
line_nr: p.scanner.line_nr 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.register_var(v)
f.args << v f.args << v
@ -781,7 +771,7 @@ fn (p mut Parser) fn_args(f mut Fn) {
is_mut: is_mut is_mut: is_mut
ptr: is_mut ptr: is_mut
line_nr: p.scanner.line_nr 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.register_var(v)
f.args << v f.args << v

View File

@ -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 { fn types_to_c(types []Type, table &Table) string {
mut sb := strings.new_builder(10) mut sb := strings.new_builder(10)
for t in types { for t in types {
if t.cat != .union_ && t.cat != .struct_ { if t.cat != .union_ && t.cat != .struct_ && t.cat != .objc_interface {
continue continue
} }
//if is_objc {
//sb.writeln('@interface $name : $objc_parent { @public')
//}
//if is_atomic { //if is_atomic {
//sb.write('_Atomic ') //sb.write('_Atomic ')
//} //}
kind := if t.cat == .union_ {'union'} else {'struct'} if t.cat == .objc_interface {
sb.writeln('$kind $t.name {') 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 { for field in t.fields {
sb.write('\t') sb.write('\t')
sb.writeln(table.cgen_name_type_pair(field.name, sb.writeln(table.cgen_name_type_pair(field.name,
field.typ) + ';') field.typ) + ';')
} }
sb.writeln('};\n') sb.writeln('};\n')
//if is_objc { if t.cat == .objc_interface {
//sb.writeln('@end') sb.writeln('@end')
//} }
} }
return sb.str() return sb.str()
} }

View File

@ -492,14 +492,17 @@ fn key_to_type_cat(tok Token) TypeCategory {
// also unions and interfaces // also unions and interfaces
fn (p mut Parser) struct_decl() { fn (p mut Parser) struct_decl() {
// V can generate Objective C for integration with Cocoa // V can generate Objective C for integration with Cocoa
// `[interface:ParentInterface]` // `[objc_interface:ParentInterface]`
//is_objc := p.attr.starts_with('interface') is_objc := p.attr.starts_with('objc_interface')
//objc_parent := if is_objc { p.attr.right(10) } else { '' } objc_parent := if is_objc { p.attr.right(15) } else { '' }
// interface, union, struct // interface, union, struct
is_interface := p.tok == .key_interface is_interface := p.tok == .key_interface
is_union := p.tok == .key_union is_union := p.tok == .key_union
is_struct := p.tok == .key_struct is_struct := p.tok == .key_struct
mut cat := key_to_type_cat(p.tok) mut cat := key_to_type_cat(p.tok)
if is_objc {
cat = .objc_interface
}
p.fgen(p.tok.str() + ' ') p.fgen(p.tok.str() + ' ')
// Get type name // Get type name
p.next() p.next()
@ -530,7 +533,11 @@ fn (p mut Parser) struct_decl() {
if p.pass == .decl && p.table.known_type_fast(typ) { if p.pass == .decl && p.table.known_type_fast(typ) {
p.error('`$name` redeclared') 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'} kind := if is_union {'union'} else {'struct'}
p.gen_typedef('typedef $kind $name $name;') p.gen_typedef('typedef $kind $name $name;')
} }
@ -544,6 +551,7 @@ fn (p mut Parser) struct_decl() {
typ.is_c = is_c typ.is_c = is_c
typ.is_placeholder = false typ.is_placeholder = false
typ.cat = cat typ.cat = cat
typ.parent = objc_parent
p.table.rewrite_type(typ) p.table.rewrite_type(typ)
} }
else { else {
@ -552,6 +560,7 @@ fn (p mut Parser) struct_decl() {
mod: p.mod mod: p.mod
is_c: is_c is_c: is_c
cat: cat cat: cat
parent: objc_parent
} }
} }
// Struct `C.Foo` declaration, no body // Struct `C.Foo` declaration, no body
@ -1715,12 +1724,6 @@ fn (p mut Parser) name_expr() string {
p.error('undefined: `$name`') p.error('undefined: `$name`')
} }
else { 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`') p.error('undefined: `$orig_name`')
} }
} else { } else {
@ -2852,42 +2855,11 @@ fn (p mut Parser) array_init() string {
} }
fn (p mut Parser) struct_init(typ string) string { fn (p mut Parser) struct_init(typ string) string {
//p.gen('/* struct init */')
p.is_struct_init = true p.is_struct_init = true
t := p.table.find_type(typ) t := p.table.find_type(typ)
if p.gen_struct_init(typ, t) { return typ } if p.gen_struct_init(typ, t) { return typ }
p.scanner.fmt_out.cut(typ.len) p.scanner.fmt_out.cut(typ.len)
ptr := typ.contains('*') 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 mut did_gen_something := false
// Loop thru all struct init keys and assign values // Loop thru all struct init keys and assign values
// u := User{age:20, name:'bob'} // u := User{age:20, name:'bob'}
@ -3763,13 +3735,11 @@ fn (p mut Parser) js_decode() string {
fn (p mut Parser) attribute() { fn (p mut Parser) attribute() {
p.check(.lsbr) p.check(.lsbr)
if p.tok == .key_interface { p.attr = p.check_name()
p.check(.key_interface) if p.tok == .colon {
p.check(.colon) p.check(.colon)
p.attr = 'interface:' + p.check_name() p.attr = p.attr + ':' + p.check_name()
} else { }
p.attr = p.check_name()
}
p.check(.rsbr) p.check(.rsbr)
if p.tok == .func || (p.tok == .key_pub && p.peek() == .func) { if p.tok == .func || (p.tok == .key_pub && p.peek() == .func) {
p.fn_decl() p.fn_decl()

View File

@ -54,6 +54,7 @@ enum TypeCategory {
union_ // 5 union_ // 5
c_struct c_struct
c_typedef c_typedef
objc_interface // 8 Objective C @interface
array array
} }
@ -607,6 +608,11 @@ fn (p mut Parser) _check_types(got_, expected_ string, throw bool) bool {
// if expected == 'T' || expected.contains('<T>') { // if expected == 'T' || expected.contains('<T>') {
// return true // return true
// } // }
// TODO fn hack
if got.starts_with('fn ') && (expected.ends_with('fn') ||
expected.ends_with('Fn')) {
return true
}
// Allow pointer arithmetic // Allow pointer arithmetic
if expected=='void*' && got=='int' { if expected=='void*' && got=='int' {
return true return true

View File

@ -42,7 +42,7 @@ fn (ctx &Context) draw() {
ctx.gg.draw_line(Size / 2, 0, Size / 2, Size) // y axis ctx.gg.draw_line(Size / 2, 0, Size / 2, Size) // y axis
center := f64(Size / 2) center := f64(Size / 2)
for x := -10.0; x <= 10.0; x += 0.002 { 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 := (x + 3) * (x + 3) - 1
//y := math.sqrt(30.0 - x * x) //y := math.sqrt(30.0 - x * x)
ctx.gg.draw_rect(center + x * Scale, center - y * Scale, 1, 1, gx.Black) ctx.gg.draw_rect(center + x * Scale, center - y * Scale, 1, 1, gx.Black)

View File

@ -1,18 +1,18 @@
// Build this example with // Build this example with
// v -live message.v // v -live message.v
module main module main
import time import time
[live] [live]
fn print_message() { 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() { fn main() {
for { for {
print_message() print_message()
time.sleep_ms(500) time.sleep_ms(500)
} }
} }

View File

@ -32,6 +32,6 @@
+ o(log n) type lookup + o(log n) type lookup
- prebuilt binaries for all platforms - prebuilt binaries for all platforms
- fix interfaces - fix interfaces
- `none` keyword for optionals + `none` keyword for optionals
- table: migrate all find*** functions to optionals + table: migrate all find*** functions to optionals

View File

@ -6,7 +6,7 @@ module darwin
struct C.NSString { } struct C.NSString { }
// macOS and iOS helpers // macOS and iOS helpers
fn nsstring(s string) *NSString { pub fn nsstring(s string) *NSString {
// #return @"" ; // #return @"" ;
// println('ns $s len=$s.len') // println('ns $s len=$s.len')
# return [ [ NSString alloc ] initWithBytesNoCopy:s.str length:s.len # return [ [ NSString alloc ] initWithBytesNoCopy:s.str length:s.len

View File

@ -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() { pub fn flush_stdout() {

View File

@ -15,6 +15,7 @@ struct User {
} }
struct Context { struct Context {
mut:
first_name ui.TextBox first_name ui.TextBox
last_name ui.TextBox last_name ui.TextBox
age ui.TextBox age ui.TextBox
@ -23,6 +24,61 @@ struct Context {
txt_pos int 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() { fn main() {
mut ctx := &Context { mut ctx := &Context {
txt_pos: 10 txt_pos: 10
@ -45,30 +101,30 @@ fn main() {
} }
// TODO replace with `fn (ctx mut Context) btn_click() {` // TODO replace with `fn (ctx mut Context) btn_click() {`
fn btn_click(_ctx *Context) { fn btn_click(_ctx &Context) {
mut ctx = _ctx// TODO hack mut ctx := _ctx// TODO hack
ctx.users << User { ctx.users << User {
first_name: ctx.first_name.text() first_name: ctx.first_name.text()
last_name: ctx.last_name.text() last_name: ctx.last_name.text()
age: ctx.age.text().to_i() age: ctx.age.text().int()
} }
ctx.window.refresh() ctx.window.refresh()
} }
// TODO replace with `fn (ctx mut Context) draw() {` // TODO replace with `fn (ctx mut Context) draw() {`
fn draw(ctx *Context) { fn draw(ctx &Context) {
for i, user in ctx.users { for i, user in ctx.users {
x := 10 x := 10
y := 10 + i * CELL_HEIGHT y := 10 + i * CELL_HEIGHT
// Outer border // 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 // Vertical separators
gx.draw_line(x + CELL_WIDTH, y, x + CELL_WIDTH, y + CELL_HEIGHT) ui.draw_line(x + CELL_WIDTH, y, x + CELL_WIDTH, y + CELL_HEIGHT, gx.Gray)
gx.draw_line(x + CELL_WIDTH * 2, y, x + CELL_WIDTH * 2, y + CELL_HEIGHT) ui.draw_line(x + CELL_WIDTH * 2, y, x + CELL_WIDTH * 2, y + CELL_HEIGHT, gx.Gray)
// Text values // Text values
gx.draw_text_def(x + 5, y + 5, user.first_name) ui.draw_text_def(x + 5, y + 5, user.first_name)
gx.draw_text_def(x + 5 + CELL_WIDTH, y + 5, user.last_name) ui.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 + CELL_WIDTH * 2, y + 5, user.age.str())
} }
} }

View File

@ -28,5 +28,3 @@ pub fn reg_key_vid() {
#RegisterEventHotKey(kVK_ANSI_1, cmdKey, gMyHotKeyID, #RegisterEventHotKey(kVK_ANSI_1, cmdKey, gMyHotKeyID,
#GetApplicationEventTarget(), 0, &gMyHotKeyRef); #GetApplicationEventTarget(), 0, &gMyHotKeyRef);
} }